From d395efeb5ef1002e0b79a3eab22fcf6e3e457209 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Wed, 17 Mar 2021 08:31:56 -0700 Subject: [PATCH] fix: Add a type-checking fast path for primitive types (#755) When `Draft` is applied to a large enum type, TypeScript has to do a lot of unnecessary structural comparisons to confirm that no element of the enum matches `Function`, `Date`, `RegExp`, etc. Determining that they do match `string` or `number`, on the other hand, is trivial. This change splits `PrimitiveType` out of `AtomicObject` so that the fast path can be checked first. In https://github.com/microsoft/TypeScript/issues/42824, this cut the check time from ~2.5 seconds to ~0.3 seconds. --- compat/pre-3.7/dist/immer.d.ts | 13 ++++++++----- src/types/types-external.ts | 19 +++++++++---------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/compat/pre-3.7/dist/immer.d.ts b/compat/pre-3.7/dist/immer.d.ts index c4c376a1..afa3ae18 100644 --- a/compat/pre-3.7/dist/immer.d.ts +++ b/compat/pre-3.7/dist/immer.d.ts @@ -5,6 +5,8 @@ type Tail = ((...t: T) => any) extends ( ? TT : [] +type PrimitiveType = number | string | boolean + /** Object types that should never be mapped */ type AtomicObject = | Function @@ -13,11 +15,10 @@ type AtomicObject = | Promise | Date | RegExp - | Boolean - | Number - | String -export type Draft = T extends AtomicObject +export type Draft = T extends PrimitiveType + ? T + : T extends AtomicObject ? T : T extends Map ? DraftMap @@ -34,7 +35,9 @@ interface DraftMap extends Map, Draft> {} interface DraftSet extends Set> {} /** Convert a mutable type into a readonly type */ -export type Immutable = T extends AtomicObject +export type Immutable = T extends PrimitiveType + ? T + : T extends AtomicObject ? T : T extends Map // Ideally, but wait for TS 3.7: ? Omit, "set" | "delete" | "clear"> ? ImmutableMap diff --git a/src/types/types-external.ts b/src/types/types-external.ts index 0dbd8f86..53a73afa 100644 --- a/src/types/types-external.ts +++ b/src/types/types-external.ts @@ -7,15 +7,10 @@ type Tail = ((...t: T) => any) extends ( ? TT : [] +type PrimitiveType = number | string | boolean + /** Object types that should never be mapped */ -type AtomicObject = - | Function - | Promise - | Date - | RegExp - | Boolean - | Number - | String +type AtomicObject = Function | Promise | Date | RegExp /** * If the lib "ES2105.collections" is not included in tsconfig.json, @@ -42,7 +37,9 @@ type WeakReferences = IfAvailable> | IfAvailable> export type WritableDraft = {-readonly [K in keyof T]: Draft} -export type Draft = T extends AtomicObject +export type Draft = T extends PrimitiveType + ? T + : T extends AtomicObject ? T : T extends IfAvailable> // Map extends ReadonlyMap ? Map, Draft> @@ -55,7 +52,9 @@ export type Draft = T extends AtomicObject : T /** Convert a mutable type into a readonly type */ -export type Immutable = T extends AtomicObject +export type Immutable = T extends PrimitiveType + ? T + : T extends AtomicObject ? T : T extends IfAvailable> // Map extends ReadonlyMap ? ReadonlyMap, Immutable>