interface Todo {
title: string;
description: string;
completed: boolean;
}
type MyPick<T, K extends keyof T> = {
[P in K]: T[P];
};
type TodoPreview = MyPick<Todo, 'title' | 'completed'>;
const todo: TodoPreview = {
title: 'Clean room',
completed: false,
};
interface Todo {
title: string;
description: string;
}
type MyReadonly<T> = {
readonly [P in keyof T]: T[P];
};
const todo: MyReadonly<Todo> = {
title: 'Hey',
description: 'foobar',
};
todo.title = 'Hello'; // Error: cannot reassign a readonly property
todo.description = 'barFoo'; // Error: cannot reassign a readonly property
const tuple = ['tesla', 'model 3', 'model X', 'model Y'] as const;
type TupleToObject<T extends readonly (string | number)[]> = {
[X in T[number]]: X;
};
type result = TupleToObject<typeof tuple>; // expected { tesla: 'tesla', 'model 3': 'model 3', 'model X': 'model X', 'model Y': 'model Y'}
type arr1 = ['a', 'b', 'c'];
type arr2 = [3, 2, 1];
type First<T extends any[]> = T[number] extends never ? never : T[0];
// type First<T extends any[]> = T['length'] extends 0 ? never : T[0]
type MyFirst<T extends unknown[]> = T extends [infer F, ...(infer R)] ? F : never;
type head1 = First<arr1>; // expected to be 'a'
type head2 = First<arr2>; // expected to be 3
type tesla = ['tesla', 'model 3', 'model X', 'model Y'];
type spaceX = ['FALCON 9', 'FALCON HEAVY', 'DRAGON', 'STARSHIP', 'HUMAN SPACEFLIGHT'];
type Length<T extends readonly any[]> = T['length'];
type teslaLength = Length<tesla>; // expected 4
type spaceXLength = Length<spaceX>; // expected 5
type MyExclude<T, K> = T extends K ? never : T;
type Result = MyExclude<'a' | 'b' | 'c', 'a'>; // 'b' | 'c'
type ExampleType = Promise<string>
type MyAwaited<T extends Promise<unknown>> = T extends Promise<infer X>
? X extends Promise<unknown>
? MyAwaited<X>
: X
: never;
type Result = MyAwaited<ExampleType> // string
type If<T extends boolean, A, B> = T extends true ? A : B;
type A = If<true, 'a', 'b'>; // expected to be 'a'
type B = If<false, 'a', 'b'>; // expected to be 'b'
type Concat<T extends any[], K extends any[]> = T extends [...(infer A)]
? K extends [...(infer B)]
? [...A, ...B]
: never
: never;
type Concat<T extends any[], K extends any[]> = [...T, ...K];
type Result = Concat<[1, 3], [2, 5]>; // expected to be [1, 3, 2, 5]
type IsEqual<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y
? 1
: 2
? true
: false;
type Includes<T extends readonly any[], U> = T extends [infer R, ...infer Rest]
? true extends IsEqual<R, U>
? true
: Includes<Rest, U>
: false;
type isPillarMen = Includes<["Kars", "Esidisi", "Wamuu", "Santana"], "Dio">; // expected to be `false`
type Push<T extends any[], K> = [...T, K];
type Result = Push<[1, 2], '3'>; // [1, 2, '3']
type Unshift<T extends any[], K> = [K, ...T];
type Result = Unshift<[1, 2], 0> // [0, 1, 2,]
const foo = (arg1: string, arg2: number): void => {};
type MyParameters<T extends (...args: any[]) => any> = T extends (...args: infer R) => unknown ? [...R] : never;
type FunctionParamsType = MyParameters<typeof foo>; // [arg1: string, arg2: number]
const fn = (v: boolean) => {
if (v) return 1;
else return 2;
};
type MyReturnType<T extends (...args: any[]) => any> = T extends (...args: any[]) => infer R
? R
: never;
type a = MyReturnType<typeof fn>; // should be "1 | 2"
type Subsequence<T extends any[]> = T extends [infer F, ...(infer R)]
? [F, ...Subsequence<R>] | Subsequence<R>
: [];
type Subsequence<T extends any[], Prefix extends any[] = []> = T extends [infer F, ...(infer R)]
? Subsequence<R, Prefix | [...Prefix, F]>
: Prefix;
type A = Subsequence<[1, 2]>; // [] | [1] | [2] | [1, 2]
type Combination<
// [foo, bar, baz], the original T, this won't be changed
T extends string[],
// foo | bar | baz > bar | baz > baz > ... need this because T[number] is fixed
Unioned extends string = T[number],
// foo | bar | baz > foo > ... for `Unioned extends Permutated ? never : Unioned`
Permutated extends string = Unioned
> =
| Unioned
// full union: foo | bar | baz
| (Permutated extends any
? // [Permutation](https://github.com/type-challenges/type-challenges/issues/614)
// Permutation will stop when Unioned is never
// Permutation will loop each value and apply to the following
// split it: `foo Combination<bar | baz>`, `foo` and `bar | baz` are mutually exclusive
`${Permutated}${Combination<
T,
Unioned extends Permutated ? never : Unioned
>}`
: never);
type Keys = Combination<["foo", "bar", "baz"]>;
type foo = {
name: string;
age: string;
};
type coo = {
age: number;
sex: string;
};
// type Merge<F, S> = {
// [P in keyof F | keyof S]: P extends keyof S ? S[P] : P extends keyof F ? F[P] :never
// }
// type Merge<F, S> = {
// [P in keyof (F & S)]: P extends keyof S ? S[P] : P extends keyof F ? F[P] :never
// }
type Merge<T, U> = Omit<Omit<T, keyof U> & U, never>;
type Result = Merge<foo, coo>; // expected to be {name: string, age: number, sex: string}
type NodeA = {
type: "A";
name: string;
flag: number;
};
type NodeB = {
type: "B";
id: number;
flag: number;
};
type NodeC = {
type: "C";
name: string;
flag: number;
};
type Nodes = NodeA | NodeB | NodeC;
type ReplacedNodes = ReplaceKeys<
Nodes,
"name" | "flag",
{ name: number; flag: string }
>;
// {type: 'A', name: number, flag: string} | {type: 'B', id: number, flag: string} | {type: 'C', name: number, flag: string} // would replace name from string to number, replace flag from number to string.
type ReplacedNotExistKeys = ReplaceKeys<Nodes, "name", { aa: number }>;
type ReplaceKeys<
U,
T extends PropertyKey,
Y extends {
[J in PropertyKey]: any;
}
> = U extends {}
? {
[K in keyof U]: K extends keyof Y ? Y[K] : K extends T ? never : U[K];
}
: never;
type Foo = {
[key: string]: any;
foo(): void;
}
type A = RemoveIndexSignature<Foo> // expected { foo(): void }
type RemoveIndexSignature<T,K=keyof T> = {
[K in keyof T as string extends K ? never
: number extends K ? never
: symbol extends K ? never
: K]: T[K]
}
type RemoveIndexSignature<T, P=PropertyKey> = {
[K in keyof T as P extends K ? never : K extends P ? K : never]: T[K]
}
type PString1 = "";
type PString2 = "+85%";
type PString3 = "-85%";
type PString4 = "85%";
type PString5 = "85";
// type PercentageParser<
// T extends string,
// P extends string = '',
// N extends string = '',
// S extends string = ''> =
// T extends `${infer A}${infer B}` ? A extends '+'|'-' ?
// PercentageParser<B, A, N, S> : A extends '%' ?
// PercentageParser<B, P, N, A> :
// PercentageParser<B, P, `${N}${A}`, S> : [P, N, S];
type Parser1<A extends string> = A extends `${infer H}${infer _}`
? H extends "-" | "+"
? H
: ""
: "";
type Parser2<A extends string> = A extends `${infer _}%` ? "%" : "";
type Parser3<A extends string> =
A extends `${Parser1<A>}${infer M}${Parser2<A>}` ? M : "";
type PercentageParser<A extends string> = [Parser1<A>, Parser3<A>, Parser2<A>];
type R1 = PercentageParser<PString1>; // expected ['', '', '']
type R2 = PercentageParser<PString2>; // expected ["+", "85", "%"]
type R3 = PercentageParser<PString3>; // expected ["-", "85", "%"]
type R4 = PercentageParser<PString4>; // expected ["", "85", "%"]
type R5 = PercentageParser<PString5>; // expected ["", "85", ""]
// 题28
interface User {
name: string;
age: number;
address: string;
}
// type PartialByKeys<T, U extends keyof T> = {
// []
// }
// type PartialByKeys<
// T,
// K=keyof T,
// PartialOne = {[J in K & keyof T]?: T[J]|undefined},
// RequiredOne = {[J in Exclude<keyof T,K>]: T[J]},
// Intersection = PartialOne&RequiredOne,
// > =
// {[J in keyof Intersection]: Intersection[J]} ;
type PartialByKeys<T, U extends keyof T> = Merge<Partial<T>, Omit<T, U>>;
type UserPartialName = PartialByKeys<User, "name">; // { name?:string; age:number; address:string }
// 题29
type OmitByType<T, K> = {
[P in keyof T as T[P] extends K ? never : P]: T[P];
};
type OmitBoolean = OmitByType<
{
name: string;
count: number;
isReadonly: boolean;
isEnable: boolean;
},
boolean
>; // { name: string; count: number }
// 题30
// type Test = '123';
// type StringToUnion<T> = T extends `${infer A}${infer R}` ? A | StringToUnion<R> : never;
// type Result = StringToUnion<Test>; // expected to be "1" | "2" | "3"
// 题31
type GetOptional<T extends Record<string, unknown>> = {
[K in keyof T as {} extends Pick<T, K> ? K : never]: T[K];
};
// type GetOptional<T> = {
// [P in keyof T as T[P] extends Required<T>[P] ? never : P]: T[P]
// }
type I = GetOptional<{ foo: number; bar: string | undefined }>; // expected to be { bar?: string }
type Test = {} extends Pick<{ foo: number; bar?: string }, "bar">
? false
: true;
// 题32
// type RequiredKeys<T extends object, P = keyof T> =
// P extends keyof T ? T[P] extends Required<T>[P] ? P : never : never;
// type Result = RequiredKeys<{ foo: number; bar?: string }>;
// 题33
type Foo = {
a: string;
b: number;
};
type Bar = {
a: string;
c: boolean;
};
// type Diff<A, B, K = keyof A & keyof B> = {
// [P in keyof A | keyof B as P extends K ? never : P ]: P extends keyof A ? A[P] : P extends keyof B ? B[P] : never;
// };
type Diff<T, U> = Omit<T & U, keyof T & keyof U>;
type Result1 = Diff<Foo, Bar>; // { b: number, c: boolean }
type Result2 = Diff<Bar, Foo>; // { b: number, c: boolean }
// 题34
interface Model {
name: string;
age: number;
locations?: string[] | null;
}
// 这里的infer Rest是除了undefined之外的值
// type ObjectEntries<T, U = keyof T> =
// U extends keyof T ? [U, T[U] extends infer Rest | undefined ? Rest : T[U]] : never;
// -?是必选
// type ObjectEntries<T> = {
// [K in keyof T]-?: [K, [Exclude<T[K], undefined>] extends [never] ? undefined : Exclude<T[K], undefined>]
// }[keyof T]
// type ObjectEntries<T> = {
// [key in keyof T]-?: [key, T[key] extends (infer R | undefined)? R: T[key]]
// }[keyof T]
type ObjectEntries<
T extends object,
K extends keyof T = keyof T
> = K extends keyof T ? [K, Required<T>[K]] : never;
type modelEntries = ObjectEntries<Model>;
// 题35
// type Flip<T extends Record<string, any>> = {
// [K in keyof T as `${T[K]}`]: K
// }
// type t1 = Flip<{ a: "x", b: "y", c: "z" }>; // {x: 'a', y: 'b', z: 'c'}
// type t2 = Flip<{ a: 1, b: 2, c: 3 }>; // {1: 'a', 2: 'b', 3: 'c'}
// type t3 = Flip<{ a: false, b: true }>; // {false: 'a', true: 'b'}
// 题36
// const brand = {
// 全部: 'ALL',
// 本品: 'SELF',
// 竞品: 'COMPETITION',
// } as const;
// type EnumOptions<T, K = keyof T> = K extends keyof T ? {label: K; value: T[K]}[] : never;
// type s1 = EnumOptions<typeof brand>;
// 题37
// type TupleToNestedObject<T, U> = T extends [infer J extends string, ...infer K] ? Record<J, TupleToNestedObject<K, U>> : U
// type TupleToNestedObject<T extends string[], U> =
// T extends [infer K, ...infer Rest] ? K extends string
// ? { [Key in K]: Rest extends string[] ? TupleToNestedObject<Rest, U> : U }
// : never : U;
// type a = TupleToNestedObject<['a'], string> // {a: string}
// type b = TupleToNestedObject<['a', 'b'], number> // {a: {b: number}}
// type c = TupleToNestedObject<[], boolean> // boolean. if the tuple is empty, just return the U type
// 题38
const tuple = ["tesla", "model 3", "model X", "model Y"] as const;
type TupleToObject<T extends readonly any[]> = {
[P in T[number]]: P;
};
type result = TupleToObject<typeof tuple>;
// expected { tesla: 'tesla', 'model 3': 'model 3', 'model X': 'model X', 'model Y': 'model Y'}
// 题39
// type DropChar<T extends string, U extends string> =
// T extends string ? T extends `${infer A}${infer Rest}` ? `${U extends A ? "" : A}${DropChar<Rest, U>}` : '' : never;
type DropChar<
T extends string,
U extends string
> = T extends `${infer A}${U}${infer Rest}` ? DropChar<`${A}${Rest}`, U> : T;
type Butterfly = DropChar<" b u t t e r f l y ! ", " ">; // 'butterfly!'
// 题40
type Union2Intersection<U> = ((x: U) => any) extends (x: infer I) => any
? I
: undefined;
type I1 = Union2Intersection<"foo" | 42 | true>;
// 题41
type Data = {
foo: {
bar: {
value: "foobar";
count: 6;
};
included: true;
};
hello: "world";
};
// type Get<T, K extends string> =
// K extends keyof T ? T[K] : K extends `${infer S}.${infer Rest}` ? S extends keyof T
// ? Get<T[S], Rest> : never : never;
// K & keyof T 的结果就是 K ,这里只是为了处理T[K]的报错
type Get<T, K extends string> = K extends `${infer K}.${infer R}`
? Get<T[K & keyof T], R>
: T[K & keyof T];
type A = Get<Data, "hello">; // 'world'
type B = Get<Data, "foo.bar.value">; // 6
type C = Get<Data, "foo.bar">; // { value: 'foobar', count: 6 }
// 题42
type StringToNumber<N> = N extends `${infer T extends number}` ? T : never;
type T2 = StringToNumber<"2">;
// 题43[]
// type FilterOut<T extends any[], K> =
// T extends [infer A, ...infer Rest] ? A extends K ? never : FilterOut<Rest, K> : never;
// type FilterOut<T extends any[], F, U extends any[] = []> = T extends [infer K, ...infer R]
// ? [K] extends [F]
// ? FilterOut<R, F, [...U]>
// : FilterOut<R, F, [...U, K]>
// : U
type FilterOut<T extends any[], U> = T extends [infer First, ...infer Rest]
? [First] extends [U]
? FilterOut<Rest, U>
: [First, ...FilterOut<Rest, U>]
: T;
type Filtered = FilterOut<[1, 2, null, 3], null>; // [1, 2, 3]