Skip to content

Commit c338a99

Browse files
authored
ci: βž• add supported TypeScript type checks (ts-essentials#283)
* ci: βž• add typecheck * ci: πŸ”„ use different job for every TS version * ci: πŸ”„ typo: @typescript => typescript * build: βž• add setTsVersion * fix: πŸ§ͺ ts4.1 * build: βž• add setTsVersion * fix: πŸ§ͺ prettier for ts-version * fix: πŸ§ͺ ts4.2 * docs: πŸ“„ changeset * docs: πŸ“„ changeset (2) * docs: ❌ remove testing for changeset
1 parent bf05a7e commit c338a99

File tree

7 files changed

+277
-40
lines changed

7 files changed

+277
-40
lines changed

β€Ž.changeset/young-readers-cheer.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"ts-essentials": patch
3+
---
4+
5+
Fix `DeepOmit` and `DeepPick` for WeakMap in TypeScript 4.1 and 4.2

β€Ž.github/workflows/typecheck.yml

+148
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
name: CI
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches:
7+
- master
8+
9+
jobs:
10+
typecheck4_1:
11+
name: TypeScript 4.1
12+
strategy:
13+
matrix:
14+
node: ['10.x']
15+
os: [ubuntu-latest]
16+
runs-on: ${{ matrix.os }}
17+
18+
steps:
19+
- uses: actions/checkout@v1
20+
- uses: actions/setup-node@v1
21+
with:
22+
node-version: ${{ matrix.node }}
23+
24+
- name: Cache YARN dependencies
25+
uses: actions/cache@v2
26+
with:
27+
path: |
28+
node_modules
29+
key: ${{ runner.OS }}-${{ matrix.node }}-yarn-cache-${{ hashFiles('yarn.lock') }}
30+
restore-keys: ${{ runner.OS }}-${{ matrix.node }}-yarn-cache-
31+
32+
- run: yarn --no-progress --non-interactive --frozen-lockfile
33+
34+
# TypeScript 4.1
35+
- run: yarn add [email protected]
36+
- run: yarn test
37+
38+
typecheck4_2:
39+
name: TypeScript 4.2
40+
strategy:
41+
matrix:
42+
node: ['10.x']
43+
os: [ubuntu-latest]
44+
runs-on: ${{ matrix.os }}
45+
46+
steps:
47+
- uses: actions/checkout@v1
48+
- uses: actions/setup-node@v1
49+
with:
50+
node-version: ${{ matrix.node }}
51+
52+
- name: Cache YARN dependencies
53+
uses: actions/cache@v2
54+
with:
55+
path: |
56+
node_modules
57+
key: ${{ runner.OS }}-${{ matrix.node }}-yarn-cache-${{ hashFiles('yarn.lock') }}
58+
restore-keys: ${{ runner.OS }}-${{ matrix.node }}-yarn-cache-
59+
60+
- run: yarn --no-progress --non-interactive --frozen-lockfile
61+
62+
# TypeScript 4.2
63+
- run: yarn add [email protected]
64+
- run: yarn test
65+
66+
typecheck4_3:
67+
name: TypeScript 4.3
68+
strategy:
69+
matrix:
70+
node: ['10.x']
71+
os: [ubuntu-latest]
72+
runs-on: ${{ matrix.os }}
73+
74+
steps:
75+
- uses: actions/checkout@v1
76+
- uses: actions/setup-node@v1
77+
with:
78+
node-version: ${{ matrix.node }}
79+
80+
- name: Cache YARN dependencies
81+
uses: actions/cache@v2
82+
with:
83+
path: |
84+
node_modules
85+
key: ${{ runner.OS }}-${{ matrix.node }}-yarn-cache-${{ hashFiles('yarn.lock') }}
86+
restore-keys: ${{ runner.OS }}-${{ matrix.node }}-yarn-cache-
87+
88+
- run: yarn --no-progress --non-interactive --frozen-lockfile
89+
90+
# TypeScript 4.3
91+
- run: yarn add [email protected]
92+
- run: yarn test
93+
94+
typecheck4_4:
95+
name: TypeScript 4.4
96+
strategy:
97+
matrix:
98+
node: ['10.x']
99+
os: [ubuntu-latest]
100+
runs-on: ${{ matrix.os }}
101+
102+
steps:
103+
- uses: actions/checkout@v1
104+
- uses: actions/setup-node@v1
105+
with:
106+
node-version: ${{ matrix.node }}
107+
108+
- name: Cache YARN dependencies
109+
uses: actions/cache@v2
110+
with:
111+
path: |
112+
node_modules
113+
key: ${{ runner.OS }}-${{ matrix.node }}-yarn-cache-${{ hashFiles('yarn.lock') }}
114+
restore-keys: ${{ runner.OS }}-${{ matrix.node }}-yarn-cache-
115+
116+
- run: yarn --no-progress --non-interactive --frozen-lockfile
117+
118+
# TypeScript 4.4
119+
- run: yarn add [email protected]
120+
- run: yarn test
121+
122+
typecheck4_5:
123+
name: TypeScript 4.5
124+
strategy:
125+
matrix:
126+
node: ['10.x']
127+
os: [ubuntu-latest]
128+
runs-on: ${{ matrix.os }}
129+
130+
steps:
131+
- uses: actions/checkout@v1
132+
- uses: actions/setup-node@v1
133+
with:
134+
node-version: ${{ matrix.node }}
135+
136+
- name: Cache YARN dependencies
137+
uses: actions/cache@v2
138+
with:
139+
path: |
140+
node_modules
141+
key: ${{ runner.OS }}-${{ matrix.node }}-yarn-cache-${{ hashFiles('yarn.lock') }}
142+
restore-keys: ${{ runner.OS }}-${{ matrix.node }}-yarn-cache-
143+
144+
- run: yarn --no-progress --non-interactive --frozen-lockfile
145+
146+
# TypeScript 4.5
147+
- run: yarn add [email protected]
148+
- run: yarn test

β€Žlib/types.ts

+43-25
Original file line numberDiff line numberDiff line change
@@ -232,35 +232,43 @@ export type DeepOmit<T, Filter extends DeepModify<T>> = T extends Builtin
232232
? T
233233
: T extends Map<infer KeyType, infer ValueType>
234234
? Filter extends Map<KeyType, infer FilterValueType>
235-
? Map<KeyType, DeepOmit<ValueType, FilterValueType>>
235+
? // @ts-ignore
236+
Map<KeyType, DeepOmit<ValueType, FilterValueType>>
236237
: T
237238
: T extends ReadonlyMap<infer KeyType, infer ValueType>
238239
? Filter extends ReadonlyMap<KeyType, infer FilterValueType>
239-
? ReadonlyMap<KeyType, DeepOmit<ValueType, FilterValueType>>
240+
? // @ts-ignore
241+
ReadonlyMap<KeyType, DeepOmit<ValueType, FilterValueType>>
240242
: T
241243
: T extends WeakMap<infer KeyType, infer ValueType>
242244
? Filter extends WeakMap<KeyType, infer FilterValueType>
243-
? WeakMap<KeyType, DeepOmit<ValueType, FilterValueType>>
245+
? // @ts-ignore
246+
WeakMap<KeyType, DeepOmit<ValueType, FilterValueType>>
244247
: T
245248
: T extends Set<infer ItemType>
246249
? Filter extends Set<infer FilterItemType>
247-
? Set<DeepOmit<ItemType, FilterItemType>>
250+
? // @ts-ignore
251+
Set<DeepOmit<ItemType, FilterItemType>>
248252
: T
249253
: T extends ReadonlySet<infer ItemType>
250254
? Filter extends ReadonlySet<infer FilterItemType>
251-
? ReadonlySet<DeepOmit<ItemType, FilterItemType>>
255+
? // @ts-ignore
256+
ReadonlySet<DeepOmit<ItemType, FilterItemType>>
252257
: T
253258
: T extends WeakSet<infer ItemType>
254259
? Filter extends WeakSet<infer FilterItemType>
255-
? WeakSet<DeepOmit<ItemType, FilterItemType>>
260+
? // @ts-ignore
261+
WeakSet<DeepOmit<ItemType, FilterItemType>>
256262
: T
257263
: T extends Array<infer ItemType>
258264
? Filter extends Array<infer FilterItemType>
259-
? Array<DeepOmit<ItemType, FilterItemType>>
265+
? // @ts-ignore
266+
Array<DeepOmit<ItemType, FilterItemType>>
260267
: T
261268
: T extends Promise<infer ItemType>
262269
? Filter extends Promise<infer FilterItemType>
263-
? Promise<DeepOmit<ItemType, FilterItemType>>
270+
? // @ts-ignore
271+
Promise<DeepOmit<ItemType, FilterItemType>>
264272
: T
265273
: Filter extends Record<string, unknown>
266274
? {
@@ -282,35 +290,43 @@ export type DeepPick<T, Filter extends DeepModify<T>> = T extends Builtin
282290
? T
283291
: T extends Map<infer KeyType, infer ValueType>
284292
? Filter extends Map<KeyType, infer FilterValueType>
285-
? Map<KeyType, DeepPick<ValueType, FilterValueType>>
293+
? // @ts-ignore
294+
Map<KeyType, DeepPick<ValueType, FilterValueType>>
286295
: T
287296
: T extends ReadonlyMap<infer KeyType, infer ValueType>
288297
? Filter extends ReadonlyMap<KeyType, infer FilterValueType>
289-
? ReadonlyMap<KeyType, DeepPick<ValueType, FilterValueType>>
298+
? // @ts-ignore
299+
ReadonlyMap<KeyType, DeepPick<ValueType, FilterValueType>>
290300
: T
291301
: T extends WeakMap<infer KeyType, infer ValueType>
292302
? Filter extends WeakMap<KeyType, infer FilterValueType>
293-
? WeakMap<KeyType, DeepPick<ValueType, FilterValueType>>
303+
? // @ts-ignore
304+
WeakMap<KeyType, DeepPick<ValueType, FilterValueType>>
294305
: T
295306
: T extends Set<infer ItemType>
296307
? Filter extends Set<infer FilterItemType>
297-
? Set<DeepPick<ItemType, FilterItemType>>
308+
? // @ts-ignore
309+
Set<DeepPick<ItemType, FilterItemType>>
298310
: T
299311
: T extends ReadonlySet<infer ItemType>
300312
? Filter extends ReadonlySet<infer FilterItemType>
301-
? ReadonlySet<DeepPick<ItemType, FilterItemType>>
313+
? // @ts-ignore
314+
ReadonlySet<DeepPick<ItemType, FilterItemType>>
302315
: T
303316
: T extends WeakSet<infer ItemType>
304317
? Filter extends WeakSet<infer FilterItemType>
305-
? WeakSet<DeepPick<ItemType, FilterItemType>>
318+
? // @ts-ignore
319+
WeakSet<DeepPick<ItemType, FilterItemType>>
306320
: T
307321
: T extends Array<infer ItemType>
308322
? Filter extends Array<infer FilterItemType>
309-
? Array<DeepPick<ItemType, FilterItemType>>
323+
? // @ts-ignore
324+
Array<DeepPick<ItemType, FilterItemType>>
310325
: T
311326
: T extends Promise<infer ItemType>
312327
? Filter extends Promise<infer FilterItemType>
313-
? Promise<DeepPick<ItemType, FilterItemType>>
328+
? // @ts-ignore
329+
Promise<DeepPick<ItemType, FilterItemType>>
314330
: T
315331
: Filter extends Record<string, unknown>
316332
? {
@@ -323,15 +339,17 @@ export type DeepPick<T, Filter extends DeepModify<T>> = T extends Builtin
323339
: never;
324340

325341
type DeepModify<T> =
326-
| {
327-
[K in keyof T]?: undefined extends { [K2 in keyof T]: K2 }[K]
328-
? NonUndefinable<T[K]> extends object
329-
? true | DeepModify<NonUndefinable<T[K]>>
330-
: true
331-
: T[K] extends object
332-
? true | DeepModify<T[K]>
333-
: true;
334-
}
342+
| (T extends Record<string, unknown>
343+
? {
344+
[K in keyof T]?: undefined extends { [K2 in keyof T]: K2 }[K]
345+
? NonUndefinable<T[K]> extends object
346+
? true | DeepModify<NonUndefinable<T[K]>>
347+
: true
348+
: T[K] extends object
349+
? true | DeepModify<T[K]>
350+
: true;
351+
}
352+
: never)
335353
| (T extends Array<infer E> ? Array<DeepModify<E>> : never)
336354
| (T extends Promise<infer E> ? Promise<DeepModify<E>> : never)
337355
| (T extends Set<infer E> ? Set<DeepModify<E>> : never)

β€Žpackage.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@
1818
"author": "Krzysztof Kaczor <[email protected]>",
1919
"license": "MIT",
2020
"scripts": {
21+
"postinstall": "yarn setTsVersion",
2122
"build": "rimraf ./dist && tsc -p tsconfig.prod.json --outDir ./dist",
2223
"formatDeclarations": "prettier --ignore-path *.js --write dist/*.d.ts",
2324
"prepublishOnly": "yarn test && yarn build && yarn formatDeclarations",
2425
"test": "prettier -c **/*.ts && tsc --noEmit",
2526
"test:fix": "prettier --write **/*.ts && tsc --noEmit",
2627
"prerelease": "yarn test",
27-
"release": "yarn build && yarn formatDeclarations && yarn changeset publish"
28+
"release": "yarn build && yarn formatDeclarations && yarn changeset publish",
29+
"setTsVersion": "node scripts/sync-ts-version.js"
2830
},
2931
"files": [
3032
"dist"

β€Žscripts/sync-ts-version.js

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// @ts-check
2+
const fs = require("fs");
3+
4+
const FIRST_TYPESCRIPT_LINE = /typescript\@\^?(\d+.\d+(.\d+)?):/;
5+
const TYPESCRIPT_VERSION_LINE = /version "(\d+.\d+)(.\d+)?"/;
6+
7+
/**
8+
* Finds TypeScript version in a filename
9+
*
10+
* @param {string} filename
11+
* @returns {string | undefined}
12+
*/
13+
const findTsVersion = (filename) => {
14+
try {
15+
const data = fs.readFileSync(filename, "utf8");
16+
const lines = data.split("\n").map((line) => line.trim());
17+
const typescriptLineIndex = lines.findIndex((line) => FIRST_TYPESCRIPT_LINE.test(line));
18+
const matched = lines[typescriptLineIndex + 1].match(TYPESCRIPT_VERSION_LINE);
19+
if (matched !== null) {
20+
return matched[1];
21+
}
22+
return undefined;
23+
} catch {
24+
return undefined;
25+
}
26+
};
27+
28+
/**
29+
*
30+
*
31+
* @param {string} tsVersion
32+
*/
33+
const writeTsVersion = (tsVersion, filename) => {
34+
fs.writeFileSync(filename, `export type TsVersion = "${tsVersion}";\n`);
35+
};
36+
37+
const tsVersion = findTsVersion("yarn.lock");
38+
if (tsVersion === undefined) {
39+
throw new Error("Cannot find TypeScript version in yarn.lock");
40+
}
41+
writeTsVersion(tsVersion, "test/ts-version.ts");

0 commit comments

Comments
Β (0)