Skip to content

Commit

Permalink
ci: πŸ“¦ add typecheck for 5.3 and 5.4 (#382)
Browse files Browse the repository at this point in the history
* ci: πŸ“¦ add typecheck for 5.3 and 5.4

* test: πŸ§ͺ comment 'as const' examples

* fix: πŸ§ͺ WeakSet & WeakMap

* docs: πŸ“„ changeset
  • Loading branch information
Beraliv committed Apr 6, 2024
1 parent 852a08f commit f88f757
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 25 deletions.
5 changes: 5 additions & 0 deletions .changeset/short-hairs-flash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ts-essentials": patch
---

Add TypeScript 5.3 and 5.4 support (fix a bug with `WeakKey` for `WeakSet` and `WeakMap`)
17 changes: 16 additions & 1 deletion .github/workflows/typecheck.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,22 @@ jobs:
node: ["14.x"]
os: [ubuntu-latest]
typescript:
["4.1.5", "4.2.4", "4.3.5", "4.4.4", "4.5.5", "4.6.4", "4.7.4", "4.8.4", "4.9.4", "5.0.4", "5.1.6", "5.2.2"]
[
"4.1.5",
"4.2.4",
"4.3.5",
"4.4.4",
"4.5.5",
"4.6.4",
"4.7.4",
"4.8.4",
"4.9.4",
"5.0.4",
"5.1.6",
"5.2.2",
"5.3.3",
"5.4.3",
]
runs-on: ${{ matrix.os }}

steps:
Expand Down
12 changes: 10 additions & 2 deletions lib/deep-nullable/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,21 @@ export type DeepNullable<Type> = Type extends Builtin
: Type extends ReadonlyMap<infer Keys, infer Values>
? ReadonlyMap<DeepNullable<Keys>, DeepNullable<Values>>
: Type extends WeakMap<infer Keys, infer Values>
? WeakMap<DeepNullable<Keys>, DeepNullable<Values>>
? // TODO: replace it with WeakKey (introduced at TypeScript@5.2)
// WeakMap key has to satisfy WeakKey which is object at the moment
DeepNullable<Keys> extends object
? WeakMap<DeepNullable<Keys>, DeepNullable<Values>>
: never
: Type extends Set<infer Values>
? Set<DeepNullable<Values>>
: Type extends ReadonlySet<infer Values>
? ReadonlySet<DeepNullable<Values>>
: Type extends WeakSet<infer Values>
? WeakSet<DeepNullable<Values>>
? // TODO: replace it with WeakKey (introduced at TypeScript@5.2)
// WeakSet key has to satisfy WeakKey which is object at the moment
DeepNullable<Values> extends object
? WeakSet<DeepNullable<Values>>
: never
: Type extends ReadonlyArray<infer Values>
? Type extends IsTuple<Type>
? { [Key in keyof Type]: DeepNullable<Type[Key]> | null }
Expand Down
12 changes: 10 additions & 2 deletions lib/deep-undefinable/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,21 @@ export type DeepUndefinable<Type> = Type extends Builtin
: Type extends ReadonlyMap<infer Keys, infer Values>
? ReadonlyMap<DeepUndefinable<Keys>, DeepUndefinable<Values>>
: Type extends WeakMap<infer Keys, infer Values>
? WeakMap<DeepUndefinable<Keys>, DeepUndefinable<Values>>
? // TODO: replace it with WeakKey (introduced at TypeScript@5.2)
// WeakMap key has to satisfy WeakKey which is object at the moment
DeepUndefinable<Keys> extends object
? WeakMap<DeepUndefinable<Keys>, DeepUndefinable<Values>>
: never
: Type extends Set<infer Values>
? Set<DeepUndefinable<Values>>
: Type extends ReadonlySet<infer Values>
? ReadonlySet<DeepUndefinable<Values>>
: Type extends WeakSet<infer Values>
? WeakSet<DeepUndefinable<Values>>
? // TODO: replace it with WeakKey (introduced at TypeScript@5.2)
// WeakSet key has to satisfy WeakKey which is object at the moment
DeepUndefinable<Values> extends object
? WeakSet<DeepUndefinable<Values>>
: never
: Type extends ReadonlyArray<infer Values>
? Type extends IsTuple<Type>
? { [Key in keyof Type]: DeepUndefinable<Type[Key]> | undefined }
Expand Down
40 changes: 20 additions & 20 deletions test/deep-pick.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ function testDeepPickInRequiredObject() {
// @ts-expect-error
obj5 = { nested: { array: undefined } };
obj5 = { nested: { array: [] } };
// @ts-expect-error
obj5 = { nested: { array: [] as const } };
// It doesn't throw TypeError for TypeScript>=5.3
// obj5 = { nested: { array: [] as const } };
// @ts-expect-error
obj5 = { nested: { array: ["1"] } };
// @ts-expect-error
Expand All @@ -81,8 +81,8 @@ function testDeepPickInRequiredObject() {
// @ts-expect-error
obj5_1 = { nested: { array: undefined } };
obj5_1 = { nested: { array: [] } };
// @ts-expect-error
obj5_1 = { nested: { array: [] as const } };
// It doesn't throw TypeError for TypeScript>=5.3
// obj5_1 = { nested: { array: [] as const } };
// @ts-expect-error
obj5_1 = { nested: { array: ["1"] } };
// @ts-expect-error
Expand All @@ -101,8 +101,8 @@ function testDeepPickInRequiredObject() {
// @ts-expect-error
obj6 = { nested: { tuple: [] as const } };
obj6 = { nested: { tuple: ["1", 2, { good: true }] } };
// @ts-expect-error
obj6 = { nested: { tuple: ["1", 2, { good: true }] as const } };
// It doesn't throw TypeError for TypeScript>=5.3
// obj6 = { nested: { tuple: ["1", 2, { good: true }] as const } };

let obj6_1: DeepPick<ComplexNestedRequired, { nested: { tuple: never } }>;
// @ts-expect-error
Expand All @@ -116,8 +116,8 @@ function testDeepPickInRequiredObject() {
// @ts-expect-error
obj6_1 = { nested: { tuple: [] as const } };
obj6_1 = { nested: { tuple: ["1", 2, { good: true }] } };
// @ts-expect-error
obj6_1 = { nested: { tuple: ["1", 2, { good: true }] as const } };
// It doesn't throw TypeError for TypeScript>=5.3
// obj6_1 = { nested: { tuple: ["1", 2, { good: true }] as const } };

let obj7: DeepPick<ComplexNestedRequired, { nested: { set: true } }>;
// @ts-expect-error
Expand Down Expand Up @@ -268,8 +268,8 @@ function testDeepPickInPartialObject() {
obj5 = { nested: undefined };
obj5 = { nested: { array: undefined } };
obj5 = { nested: { array: [] } };
// @ts-expect-error
obj5 = { nested: { array: [] as const } };
// It doesn't throw TypeError for TypeScript>=5.3
// obj5 = { nested: { array: [] as const } };
// @ts-expect-error
obj5 = { nested: { array: ["1"] } };
// @ts-expect-error
Expand All @@ -281,8 +281,8 @@ function testDeepPickInPartialObject() {
obj5_1 = { nested: undefined };
obj5_1 = { nested: { array: undefined } };
obj5_1 = { nested: { array: [] } };
// @ts-expect-error
obj5_1 = { nested: { array: [] as const } };
// It doesn't throw TypeError for TypeScript>=5.3
// obj5_1 = { nested: { array: [] as const } };
// @ts-expect-error
obj5_1 = { nested: { array: ["1"] } };
// @ts-expect-error
Expand All @@ -294,22 +294,22 @@ function testDeepPickInPartialObject() {
obj6 = { nested: undefined };
obj6 = { nested: { tuple: undefined } };
obj6 = { nested: { tuple: [] } };
// @ts-expect-error
obj6 = { nested: { tuple: [] as const } };
// It doesn't throw TypeError for TypeScript>=5.3
// obj6 = { nested: { tuple: [] as const } };
obj6 = { nested: { tuple: ["1", 2, { good: true }] } };
// @ts-expect-error
obj6 = { nested: { tuple: ["1", 2, { good: true }] as const } };
// It doesn't throw TypeError for TypeScript>=5.3
// obj6 = { nested: { tuple: ["1", 2, { good: true }] as const } };

let obj6_1: DeepPick<ComplexNestedPartial, { nested: { tuple: never } }>;
obj6_1 = {};
obj6_1 = { nested: undefined };
obj6_1 = { nested: { tuple: undefined } };
obj6_1 = { nested: { tuple: [] } };
// @ts-expect-error
obj6_1 = { nested: { tuple: [] as const } };
// It doesn't throw TypeError for TypeScript>=5.3
// obj6_1 = { nested: { tuple: [] as const } };
obj6_1 = { nested: { tuple: ["1", 2, { good: true }] } };
// @ts-expect-error
obj6_1 = { nested: { tuple: ["1", 2, { good: true }] as const } };
// It doesn't throw TypeError for TypeScript>=5.3
// obj6_1 = { nested: { tuple: ["1", 2, { good: true }] as const } };

let obj7: DeepPick<ComplexNestedPartial, { nested: { set: true } }>;
obj7 = {};
Expand Down
2 changes: 2 additions & 0 deletions test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ function testDeepNullable() {
Assert<IsExact<DeepNullable<Set<number[]>>, Set<(number | null)[]>>>,
Assert<IsExact<DeepNullable<Set<readonly number[]>>, Set<readonly (number | null)[]>>>,
Assert<IsExact<DeepNullable<ReadonlySet<string>>, ReadonlySet<string | null>>>,
Assert<IsExact<DeepNullable<WeakSet<{ a: string }>>, WeakSet<{ a: string | null }>>>,
Assert<IsExact<DeepNullable<[]>, []>>,
Assert<IsExact<DeepNullable<readonly []>, readonly []>>,
Assert<IsExact<DeepNullable<never[]>, null[]>>,
Expand Down Expand Up @@ -316,6 +317,7 @@ function testDeepUndefinable() {
Assert<IsExact<DeepUndefinable<Set<number[]>>, Set<(number | undefined)[]>>>,
Assert<IsExact<DeepUndefinable<Set<readonly number[]>>, Set<readonly (number | undefined)[]>>>,
Assert<IsExact<DeepUndefinable<ReadonlySet<string>>, ReadonlySet<string | undefined>>>,
Assert<IsExact<DeepUndefinable<WeakSet<{ a: string }>>, WeakSet<{ a: string | undefined }>>>,
Assert<IsExact<DeepUndefinable<[]>, []>>,
Assert<IsExact<DeepUndefinable<readonly []>, readonly []>>,
Assert<IsExact<DeepUndefinable<never[]>, undefined[]>>,
Expand Down

0 comments on commit f88f757

Please sign in to comment.