/** * Implement an `AssignAll` generic that takes a tuple * containing object types and merges all of them. * * Bonus: make it *Tail-Recursive*. */namespace assign { declare function assign< // Infer `Objects` as a tuple of objects: Objects extends [{}, ...{}[]] >(...objects: Objects): AssignAll<Objects>; type AssignAll<Tuple> = Tuple extends [infer Obj, ...infer Rest] ? Obj & AssignAll<Rest> : {} // Two objects const res1 = assign({ name: "Michel", age: 82 }, { childrenCount: 3 }); type expected1 = { name: string; age: number, childrenCount: number }; type test1 = Expect<Equal<typeof res1, expected1>>; // Three objects const res2 = assign( { protocol: "https" as const }, { domain: "type-level-typescript.com" }, { path: "/recursive-types" } ); type expected2 = { protocol: "https", domain: string, path: string}; type test2 = Expect<Equal<typeof res2, expected2>>; // Five objects const res3 = assign( { a: true }, { b: 2 }, { c: "4" }, { d: null }, { 2: 2n }); type expected3 = { a: boolean; b: number; c: string; d: null; 2: bigint }; type test3 = Expect<Equal<typeof res3, expected3>>; // One object const res4 = assign({ fileName: "hello-world", extension: "txt" }); type expected4 = { fileName: string; extension: string }; type test4 = Expect<Equal<typeof res4, expected4>>;}
/** * Type the `all` function to take a list of promises and * to turn them into a single promise containing a list of values. */namespace promiseAll { declare function all< // Infer `Promises` as a tuple of promises: Promises extends [Promise<any>, ...Promise<any>[]], >(promises: Promises): Promise<UnwrapAll<Promises>>; type UnwrapAll<Promises> = Promises extends [Promise<infer R>, ...infer Rest] ? [R, ...UnwrapAll<Rest>] : []; // Two promises const res1 = all([Promise.resolve(20), Promise.resolve("Hello" as const)]); type expected1 = Promise<[number, "Hello"]>; type test1 = Expect<Equal<typeof res1, expected1>>; // Three promises const res2 = all([ Promise.resolve(true), Promise.resolve("!"), Promise.resolve({}), ]); type expected2 = Promise<[boolean, string, {}]>; type test2 = Expect<Equal<typeof res2, expected2>>; // Five promises const res3 = all([ Promise.resolve(3), Promise.resolve("Hello" as const), Promise.resolve(true), Promise.resolve({ key: "value" }), Promise.resolve(["array"]), ]); type expected3 = Promise< [number, "Hello", boolean, { key: string }, string[]] >; type test3 = Expect<Equal<typeof res3, expected3>>;}
/** * Type the `filterTable` function to take a Table, * a list of column names, and to return a table that * only contains columns with these names. */namespace filterTable { type Column = { name: string, values: unknown[] } declare function filterTable< // Infer `T` as a tuple containing columns: T extends [Column, ...Column[]], // Infer `N` as a union of string literal type: N extends string >(table: T, columnNames: N[]): FilterTable<T, N>; type FilterTable<Table, NameUnion> = Table extends [infer A, ...infer B] ? A extends {"name": NameUnion} ? [A, ...FilterTable<B, NameUnion>] : FilterTable<B, NameUnion> : [] declare const userTable: [ { name: 'firstName', values: string[] }, { name: 'lastName', values: string[] }, { name: 'age', values: number[] }, ] const res1 = filterTable(userTable, ['age']); type test1 = Expect<Equal<typeof res1, [ { name: 'age', values: number[] } ]>>; const res2 = filterTable(userTable, ['firstName', 'lastName']); type test2 = Expect<Equal<typeof res2, [ { name: 'firstName', values: string[] }, { name: 'lastName', values: string[] } ]>>; const res3 = filterTable(userTable, []); type test3 = Expect<Equal<typeof res3, []>>;}
이거 벽느낌…
/** * Type lodash's `zip` function. * `zip` takes several arrays containing different types of * values, and turn them into a single array containing * tuples of values for each index. * * For example, `zip([1, 2], [true, false], ['a', 'b'])` * returns `[[1, true, 'a'], [2, false, 'b']]`. */namespace zip { declare function zip<Arrays extends [any[], ...any[][]]>(...arrays: Arrays): UnwrapList<Arrays>[]; type UnwrapList<T> = T extends [(infer A)[], ...infer B] ? [A, ...UnwrapList<B>] : [] const res1 = zip([1, 2], [true, false]); // => [[1, true], [2, false]] type test1 = Expect<Equal<typeof res1, [number, boolean][]>>; const res2 = zip([1, 2], [true, false], ['a', 'b']); // => [[1, true, 'a'], [2, false, 'b']] type test2 = Expect<Equal<typeof res2, [number, boolean, string][]>>; const res3 = zip([1, 2, null], [true, false, undefined]); // => [[1, true], [2, false], [null, undefined]] type test3 = Expect<Equal<typeof res3, [number | null, boolean | undefined][]>>;}
/** * Make a `Filter` generic that takes a tuple, * an arbitrary `Cond` type, filters out any element * that isn't assignable to `Cond`. */namespace filter { type Filter<Tuple, Cond> = Tuple extends [infer A, ...infer B] ? A extends Cond ? [A, ...Filter<B, Cond>] : Filter<B, Cond> : [] type res1 = Filter<[1, 2, "oops", 3, "hello"], number>; type test1 = Expect<Equal<res1, [1, 2, 3]>>; type res2 = Filter<["a", 1, "b", true, "c"], string>; type test2 = Expect<Equal<res2, ["a", "b", "c"]>>; type res3 = Filter<["hello", null, 42, {}, [], undefined], {}>; type test3 = Expect<Equal<res3, ["hello", 42, {}, []]>>; // ^ ^ // Note: strings and numbers are assignable to the `{}` object type.}
이상하게 풀었네..
/** * Write a `WithIndex` type level function * that takes a tuple, and maps it to a tuple * of [value, index] pairs. * * Hint: you will need to use T["length"] * to generate indices */namespace withIndex { type WithIndex< Tuple extends any[], Output extends any[] = [] > = Tuple extends [...infer A, infer B] ? WithIndex<A, [[B, A["length"]], ...Output]> : Output type res1 = WithIndex<['a']>; type test1 = Expect<Equal<res1, [['a', 0]]>>; type res2 = WithIndex<['a', 'b']>; type test2 = Expect<Equal<res2, [['a', 0], ['b', 1]]>>; type res3 = WithIndex<['a', 'b', 'c']>; type test3 = Expect<Equal<res3, [['a', 0], ['b', 1], ['c', 2]]>>;}
/** * Write a `Take` type level function * that takes a tuple, a `N` number and * returns the first `N` elements of this * tuple. * * Hint: you will need to use T["length"] * to read the length of a tuple `T`. */namespace take { type Take< Tuple extends any[], N, Output extends any[] = [] > = Tuple extends [infer A, ...infer B] ? Output["length"] extends N ? Output : Take<B, N, [...Output, A]> : Output type res1 = Take<[1, 2, 3], 2>; type test1 = Expect<Equal<res1, [1, 2]>>; type res2 = Take<[1, 2, 3], 1>; type test2 = Expect<Equal<res2, [1]>>; type res3 = Take<[1, 2, 3], 0>; type test3 = Expect<Equal<res3, []>>; type res4 = Take<[1, 2], 5>; type test4 = Expect<Equal<res4, [1, 2]>>;}