typescript-builtins-extended 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Hayden
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,15 @@
1
+ # Typescript Utilities
2
+
3
+ English | [简体中文](README.zh-CN.md)
4
+
5
+ Provides a globally-scoped type conversion tool for typescript. Unlike other tools, `typescript-builtins-extended` does not provide any js code and focuses on typescript type conversion. And it can be used directly like using built-in utility types such as `Omit` `Pick` without additional import.
6
+
7
+ Utility types and implementation methods come from [type-challenges](https://github.com/type-challenges/type-challenges.git)
8
+
9
+ ## Usage
10
+
11
+ Add the following code to the `d.ts` declaration file
12
+
13
+ ```ts
14
+ /// <reference types="typescript-builtins-extended" />
15
+ ```
@@ -0,0 +1,15 @@
1
+ # Typescript Utilities
2
+
3
+ [English](README.md) | 简体中文
4
+
5
+ 为 typescript 提供全局范围的类型转换工具,与其他工具不同,`typescript-builtins-extended` 不提供任何 js 代码,专注于 typescript 的类型转换。并且可以像使用 `Omit` `Pick` 等内置实用程序类型一样直接使用,无需额外导入。
6
+
7
+ 实用程序类型与其实现方式来源于 [type-challenges](https://github.com/type-challenges/type-challenges.git)
8
+
9
+ ## 使用
10
+
11
+ 将下面的代码添加到 `d.ts` 声明文件中
12
+
13
+ ```ts
14
+ /// <reference types="typescript-builtins-extended" />
15
+ ```
package/index.d.ts ADDED
@@ -0,0 +1,27 @@
1
+ export { }
2
+
3
+ declare global {
4
+ export type { GetReadonlyKeys } from './src/00005-extreme-readonly-keys'
5
+ import('./src/00005-extreme-readonly-keys')
6
+
7
+ export type { DeepReadonly } from './src/00009-medium-deep-readonly'
8
+ import('./src/00009-medium-deep-readonly')
9
+
10
+ export type { TupleToUnion } from './src/00010-medium-tuple-to-union'
11
+ import('./src/00010-medium-tuple-to-union')
12
+
13
+ export type { TupleToObject } from './src/00011-easy-tuple-to-object'
14
+ import('./src/00011-easy-tuple-to-object')
15
+
16
+ export type { First } from './src/00014-easy-first'
17
+ import('./src/00014-easy-first')
18
+
19
+ export type { Last } from './src/00015-medium-last'
20
+ import('./src/00015-medium-last')
21
+
22
+ export type { Pop } from './src/00016-medium-pop'
23
+ import('./src/00016-medium-pop')
24
+
25
+ export type { UnionToTuple } from './src/00730-hard-union-to-tuple'
26
+ import('./src/00730-hard-union-to-tuple')
27
+ }
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "typescript-builtins-extended",
3
+ "version": "0.0.1",
4
+ "description": "Collection of TypeScript Utility Types.",
5
+ "keywords": [
6
+ "typescript",
7
+ "utilities",
8
+ "Utility",
9
+ "types"
10
+ ],
11
+ "bugs": {
12
+ "url": "https://github.com/hayden-fr/typescript-builtins-extended/issues"
13
+ },
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "https://github.com/hayden-fr/typescript-builtins-extended.git"
17
+ },
18
+ "files": [
19
+ "src",
20
+ "index.d.ts",
21
+ "tsconfig.json"
22
+ ],
23
+ "types": "index.d.ts",
24
+ "author": "hayden <hayden.mike.zhang@gmail.com>",
25
+ "devDependencies": {
26
+ "typescript": "^5.9.2"
27
+ },
28
+ "scripts": {
29
+ "test": "tsc --noEmit"
30
+ }
31
+ }
@@ -0,0 +1,34 @@
1
+ // ============= Test Cases =============
2
+ import type { Equal, Expect } from './test-utils'
3
+
4
+ type cases = [
5
+ Expect<Equal<'title', GetReadonlyKeys<Todo1>>>,
6
+ Expect<Equal<'title' | 'description', GetReadonlyKeys<Todo2>>>,
7
+ ]
8
+
9
+ interface Todo1 {
10
+ readonly title: string
11
+ description: string
12
+ completed: boolean
13
+ }
14
+
15
+ interface Todo2 {
16
+ readonly title: string
17
+ readonly description: string
18
+ completed?: boolean
19
+ }
20
+
21
+
22
+ // ============= Your Code Here =============
23
+ // Implemented by https://github.com/type-challenges/type-challenges/issues/139
24
+
25
+ /**
26
+ * Implement a generic `GetReadonlyKeys<T>` that returns a union of the readonly keys of an Object.
27
+ *
28
+ * 实现泛型 `GetReadonlyKeys<T>`,`GetReadonlyKeys<T>` 返回由对象 T 所有只读属性的键组成的联合类型。
29
+ */
30
+ export type GetReadonlyKeys<
31
+ T,
32
+ U extends Readonly<T> = Readonly<T>,
33
+ K extends keyof T = keyof T
34
+ > = K extends keyof T ? Equal<Pick<T, K>, Pick<U, K>> extends true ? K : never : never;
@@ -0,0 +1,69 @@
1
+ // ============= Test Cases =============
2
+ import type { Equal, Expect } from './test-utils'
3
+
4
+ type cases = [
5
+ Expect<Equal<DeepReadonly<X1>, Expected1>>,
6
+ Expect<Equal<DeepReadonly<X2>, Expected2>>,
7
+ ]
8
+
9
+ type X1 = {
10
+ a: () => 22
11
+ b: string
12
+ c: {
13
+ d: boolean
14
+ e: {
15
+ g: {
16
+ h: {
17
+ i: true
18
+ j: 'string'
19
+ }
20
+ k: 'hello'
21
+ }
22
+ l: [
23
+ 'hi',
24
+ {
25
+ m: ['hey']
26
+ },
27
+ ]
28
+ }
29
+ }
30
+ }
31
+
32
+ type X2 = { a: string } | { b: number }
33
+
34
+ type Expected1 = {
35
+ readonly a: () => 22
36
+ readonly b: string
37
+ readonly c: {
38
+ readonly d: boolean
39
+ readonly e: {
40
+ readonly g: {
41
+ readonly h: {
42
+ readonly i: true
43
+ readonly j: 'string'
44
+ }
45
+ readonly k: 'hello'
46
+ }
47
+ readonly l: readonly [
48
+ 'hi',
49
+ {
50
+ readonly m: readonly ['hey']
51
+ },
52
+ ]
53
+ }
54
+ }
55
+ }
56
+
57
+ type Expected2 = { readonly a: string } | { readonly b: number }
58
+
59
+ // ============= Your Code Here =============
60
+ // Implemented by https://github.com/type-challenges/type-challenges/issues/13716
61
+
62
+ /**
63
+ * Implement a generic `DeepReadonly<T>` which make every parameter of an object - and its sub-objects recursively - readonly.
64
+ *
65
+ * 实现一个泛型 `DeepReadonly<T>`,它将对象的每个参数及其子对象递归地设为只读。
66
+ */
67
+ export type DeepReadonly<T> = {
68
+ readonly [P in keyof T]: keyof T[P] extends never ? T[P] : DeepReadonly<T[P]>
69
+ }
@@ -0,0 +1,18 @@
1
+ // ============= Test Cases =============
2
+ import type { Equal, Expect } from './test-utils'
3
+
4
+ type cases = [
5
+ Expect<Equal<TupleToUnion<[123, '456', true]>, 123 | '456' | true>>,
6
+ Expect<Equal<TupleToUnion<[123]>, 123>>,
7
+ ]
8
+
9
+
10
+ // ============= Your Code Here =============
11
+ // Implemented by https://github.com/type-challenges/type-challenges/issues/7
12
+
13
+ /**
14
+ * Implement a generic `TupleToUnion<T>` which covers the values of a tuple to its values union.
15
+ *
16
+ * 实现泛型 `TupleToUnion<T>`,它返回元组所有值的合集。
17
+ */
18
+ export type TupleToUnion<T> = T extends Array<infer ITEMS> ? ITEMS : never
@@ -0,0 +1,32 @@
1
+ // ============= Test Cases =============
2
+ import type { Equal, Expect } from './test-utils'
3
+
4
+ const tuple = ['tesla', 'model 3', 'model X', 'model Y'] as const
5
+ const tupleNumber = [1, 2, 3, 4] as const
6
+ const sym1 = Symbol(1)
7
+ const sym2 = Symbol(2)
8
+ const tupleSymbol = [sym1, sym2] as const
9
+ const tupleMix = [1, '2', 3, '4', sym1] as const
10
+
11
+ type cases = [
12
+ Expect<Equal<TupleToObject<typeof tuple>, { 'tesla': 'tesla', 'model 3': 'model 3', 'model X': 'model X', 'model Y': 'model Y' }>>,
13
+ Expect<Equal<TupleToObject<typeof tupleNumber>, { 1: 1, 2: 2, 3: 3, 4: 4 }>>,
14
+ Expect<Equal<TupleToObject<typeof tupleSymbol>, { [sym1]: typeof sym1, [sym2]: typeof sym2 }>>,
15
+ Expect<Equal<TupleToObject<typeof tupleMix>, { 1: 1, '2': '2', 3: 3, '4': '4', [sym1]: typeof sym1 }>>,
16
+ ]
17
+
18
+ // @ts-expect-error
19
+ type error = TupleToObject<[[1, 2], {}]>
20
+
21
+
22
+ // ============= Your Code Here =============
23
+ // Implemented by https://github.com/type-challenges/type-challenges/issues/5896
24
+
25
+ /**
26
+ * Given an array, transform it into an object type and the key/value must be in the provided array.
27
+ *
28
+ * 将一个元组类型转换为对象类型,这个对象类型的键/值和元组中的元素对应。
29
+ */
30
+ export type TupleToObject<T extends readonly (string | symbol | number)[]> = {
31
+ [P in T[number]]: P
32
+ }
@@ -0,0 +1,27 @@
1
+ // ============= Test Cases =============
2
+ import type { Equal, Expect } from './test-utils'
3
+
4
+ type cases = [
5
+ Expect<Equal<First<[3, 2, 1]>, 3>>,
6
+ Expect<Equal<First<[() => 123, { a: string }]>, () => 123>>,
7
+ Expect<Equal<First<[]>, never>>,
8
+ Expect<Equal<First<[undefined]>, undefined>>,
9
+ ]
10
+
11
+ type errors = [
12
+ // @ts-expect-error
13
+ First<'notArray'>,
14
+ // @ts-expect-error
15
+ First<{ 0: 'arrayLike' }>,
16
+ ]
17
+
18
+
19
+ // ============= Your Code Here =============
20
+ // Implemented by https://github.com/type-challenges/type-challenges/issues/16315
21
+
22
+ /**
23
+ * Implement a generic `First<T>` that takes an Array T and returns its first element's type.
24
+ *
25
+ * 实现一个 `First<T>` 泛型,它接受一个数组T并返回它的第一个元素的类型。
26
+ */
27
+ export type First<T extends any[]> = T extends [] ? never : T[0]
@@ -0,0 +1,20 @@
1
+ // ============= Test Cases =============
2
+ import type { Equal, Expect } from './test-utils'
3
+
4
+ type cases = [
5
+ Expect<Equal<Last<[]>, never>>,
6
+ Expect<Equal<Last<[2]>, 2>>,
7
+ Expect<Equal<Last<[3, 2, 1]>, 1>>,
8
+ Expect<Equal<Last<[() => 123, { a: string }]>, { a: string }>>,
9
+ ]
10
+
11
+
12
+ // ============= Your Code Here =============
13
+ // Implemented by https://github.com/type-challenges/type-challenges/issues/38
14
+
15
+ /**
16
+ * Implement a generic `Last<T>` that takes an Array T and returns its last element.
17
+ *
18
+ * 实现一个 `Last<T>` 泛型,它接受一个数组T并返回其最后一个元素的类型。
19
+ */
20
+ export type Last<T extends any[]> = T extends [...infer _, infer L] ? L : never
@@ -0,0 +1,22 @@
1
+ // ============= Test Cases =============
2
+ import type { Equal, Expect } from './test-utils'
3
+
4
+ type cases = [
5
+ Expect<Equal<Pop<[3, 2, 1]>, [3, 2]>>,
6
+ Expect<Equal<Pop<['a', 'b', 'c', 'd']>, ['a', 'b', 'c']>>,
7
+ Expect<Equal<Pop<[]>, []>>,
8
+ ]
9
+
10
+ // ============= Your Code Here =============
11
+ // Implemented by https://github.com/type-challenges/type-challenges/issues/37295
12
+
13
+ /**
14
+ * Implement a generic `Pop<T>` that takes an Array T and returns an Array without it's last element.
15
+ *
16
+ * 实现一个泛型 `Pop<T>`,它接受一个数组T,并返回一个由数组T的前 N-1 项(N 为数组T的长度)以相同的顺序组成的数组。
17
+ */
18
+ export type Pop<T extends any[]> = T extends []
19
+ ? []
20
+ : T extends [...infer R, infer _]
21
+ ? R
22
+ : never
@@ -0,0 +1,52 @@
1
+ // ============= Test Cases =============
2
+ import type { Equal, Expect } from './test-utils'
3
+
4
+ type ExtractValuesOfTuple<T extends any[]> = T[keyof T & number]
5
+
6
+ type cases = [
7
+ Expect<Equal<UnionToTuple<'a' | 'b'>['length'], 2>>,
8
+ Expect<Equal<ExtractValuesOfTuple<UnionToTuple<'a' | 'b'>>, 'a' | 'b'>>,
9
+ Expect<Equal<ExtractValuesOfTuple<UnionToTuple<'a'>>, 'a'>>,
10
+ Expect<Equal<ExtractValuesOfTuple<UnionToTuple<any>>, any>>,
11
+ Expect<Equal<ExtractValuesOfTuple<UnionToTuple<undefined | void | 1>>, void | 1>>,
12
+ Expect<Equal<ExtractValuesOfTuple<UnionToTuple<any | 1>>, any | 1>>,
13
+ Expect<Equal<ExtractValuesOfTuple<UnionToTuple<any | 1>>, any>>,
14
+ Expect<Equal<ExtractValuesOfTuple<UnionToTuple<'d' | 'f' | 1 | never>>, 'f' | 'd' | 1>>,
15
+ Expect<Equal<ExtractValuesOfTuple<UnionToTuple<[{ a: 1 }] | 1>>, [{ a: 1 }] | 1>>,
16
+ Expect<Equal<ExtractValuesOfTuple<UnionToTuple<never>>, never>>,
17
+ Expect<Equal<ExtractValuesOfTuple<UnionToTuple<'a' | 'b' | 'c' | 1 | 2 | 'd' | 'e' | 'f' | 'g'>>, 'f' | 'e' | 1 | 2 | 'g' | 'c' | 'd' | 'a' | 'b'>>,
18
+ ]
19
+
20
+
21
+ // ============= Your Code Here =============
22
+ // Implemented by https://github.com/type-challenges/type-challenges/issues/737
23
+
24
+ /**
25
+ * UnionToIntersection<{ foo: string } | { bar: string }> =
26
+ * { foo: string } & { bar: string }.
27
+ */
28
+ type UnionToIntersection<U> = (
29
+ U extends unknown ? (arg: U) => 0 : never
30
+ ) extends (arg: infer I) => 0
31
+ ? I
32
+ : never;
33
+
34
+ /**
35
+ * LastInUnion<1 | 2> = 2.
36
+ */
37
+ type LastInUnion<U> = UnionToIntersection<
38
+ U extends unknown ? (x: U) => 0 : never
39
+ > extends (x: infer L) => 0
40
+ ? L
41
+ : never;
42
+
43
+ /**
44
+ * Implement a type, UnionToTuple, that converts a union to a tuple.
45
+ *
46
+ * 将联合转换为元组的类型。
47
+ *
48
+ * UnionToTuple<1 | 2> = [1, 2].
49
+ */
50
+ export type UnionToTuple<U, Last = LastInUnion<U>> = [U] extends [never]
51
+ ? []
52
+ : [...UnionToTuple<Exclude<U, Last>>, Last];
@@ -0,0 +1,31 @@
1
+ export type Expect<T extends true> = T
2
+ export type ExpectTrue<T extends true> = T
3
+ export type ExpectFalse<T extends false> = T
4
+ export type IsTrue<T extends true> = T
5
+ export type IsFalse<T extends false> = T
6
+
7
+ export type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2
8
+ ? true
9
+ : false
10
+ export type NotEqual<X, Y> = true extends Equal<X, Y> ? false : true
11
+
12
+ // https://stackoverflow.com/questions/49927523/disallow-call-with-any/49928360#49928360
13
+ export type IsAny<T> = 0 extends 1 & T ? true : false
14
+ export type NotAny<T> = true extends IsAny<T> ? false : true
15
+
16
+ export type Debug<T> = { [K in keyof T]: T[K] }
17
+ export type MergeInsertions<T> = T extends object ? { [K in keyof T]: MergeInsertions<T[K]> } : T
18
+
19
+ export type Alike<X, Y> = Equal<MergeInsertions<X>, MergeInsertions<Y>>
20
+
21
+ export type ExpectExtends<VALUE, EXPECTED> = EXPECTED extends VALUE ? true : false
22
+ export type ExpectValidArgs<
23
+ FUNC extends (...args: any[]) => any,
24
+ ARGS extends any[]
25
+ > = ARGS extends Parameters<FUNC> ? true : false
26
+
27
+ export type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
28
+ k: infer I
29
+ ) => void
30
+ ? I
31
+ : never
package/tsconfig.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "compilerOptions": {
3
+ // https://www.typescriptlang.org/tsconfig/#rootDir-and-baseUrl
4
+ "rootDir": ".",
5
+ "baseUrl": ".",
6
+
7
+ // Most non-library projects don't need to emit declarations.
8
+ // So we add this option by default to make the config more friendly to most users.
9
+ "noEmit": true,
10
+
11
+ // As long as you are using a build tool, we recommend you to author and ship in ES modules.
12
+ // Even if you are targeting Node.js, because
13
+ // - `CommonJS` is too outdated
14
+ // - the ecosystem hasn't fully caught up with `Node16`/`NodeNext`
15
+ // This recommendation includes environments like Vitest, Vite Config File, Vite SSR, etc.
16
+ "module": "ESNext",
17
+
18
+ // We expect users to use bundlers.
19
+ // So here we enable some resolution features that are only available in bundlers.
20
+ "moduleResolution": "Bundler",
21
+ "resolveJsonModule": true,
22
+ "allowImportingTsExtensions": true,
23
+ // Even files without `import` or `export` are treated as modules.
24
+ // It helps to avoid mysterious errors such as `Cannot redeclare block-scoped variable 'name`.
25
+ // https://www.totaltypescript.com/cannot-redeclare-block-scoped-variable#solution-3-your-module-isnt-a-module
26
+ "moduleDetection": "force",
27
+
28
+ // `"noImplicitThis": true` is part of `strict`
29
+ // Added again here in case some users decide to disable `strict`.
30
+ // This enables stricter inference for data properties on `this`.
31
+ "noImplicitThis": true,
32
+ "strict": true,
33
+
34
+ // supports ES2016+
35
+ "target": "ESNext",
36
+
37
+ // Recommended
38
+ "skipLibCheck": true,
39
+ }
40
+ }