Skip to content

Instantly share code, notes, and snippets.

@mscolnick
Created March 15, 2021 03:55
Show Gist options
  • Save mscolnick/2d9fe95f1ca63b88f3cb318e98beb821 to your computer and use it in GitHub Desktop.
Save mscolnick/2d9fe95f1ca63b88f3cb318e98beb821 to your computer and use it in GitHub Desktop.
The Fibonacci sequence in TypeScript
type Plus1<A extends any[]> = [true, ...A];
type Add<A extends any[], B extends any[]> = [...A, ...B];
type Minus1<A extends any[]> = A extends readonly [any?, ...infer U] ? U : [...A];
type Minus2<A extends any[]> = Minus1<Minus1<A>>;
// verify
type D = Plus1<A>; // [true, true, true, true]
type E = Minus1<A>; // [true, true]
type F = Minus2<A>; // [true]
// number -> array
type ArrayOfSize<N extends number> = N extends N ? (number extends N ? boolean[] : _ArrayOfSize<N, []>) : never;
type _ArrayOfSize<N extends number, R extends unknown[]> = R['length'] extends N ? R : _ArrayOfSize<N, [true, ...R]>;
// verify
type A = ArrayOfSize<3>; // [true, true, true]
type B = ArrayOfSize<1>; // [true]
type C = ArrayOfSize<0>; // []
// array -> number
type AP = A['length']; // 3
type BP = B['length']; // 1
type CP = C['length']; // 0
type TypeName<T> =
T extends string ? "string" :
T extends number ? "number" :
T extends boolean ? "boolean" :
T extends undefined ? "undefined" :
T extends Function ? "function" :
"object";
type T0 = TypeName<string>; // "string"
type T1 = TypeName<"a">; // "string"
type T2 = TypeName<true>; // "boolean"
type T3 = TypeName<() => void>; // "function"
type T4 = TypeName<string[]>; // "object"
function fibonacci(num) {
if (num <= 1) {
return 1;
}
return fibonacci(num - 1) + fibonacci(num - 2);
}
type _Fib<NUM extends any[]> = NUM['length'] extends 1 | 0
? NUM
: Add<_Fib<Minus1<NUM>>, _Fib<Minus2<NUM>>>;
type Fib<N extends number> = _Fib<ArrayOfSize<N>>['length'];
type F1 = Fib<1>; // 1
type F2 = Fib<2>; // 1
type F3 = Fib<3>; // 2
type F4 = Fib<4>; // 3
type F5 = Fib<5>; // 5
type F6 = Fib<6>; // 8
type F7 = Fib<7>; // 13
type F8 = Fib<8>; // 21
type F9 = Fib<9>; // 34
type F20 = Fib<20>; // 6765
type F30 = Fib<30>; // Error, recursion too deep
type TypeName<T> =
T extends string ? "string" :
T extends number ? "number" :
T extends boolean ? "boolean" :
T extends undefined ? "undefined" :
T extends Function ? "function" :
"object";
type T0 = TypeName<string>; // "string"
type T1 = TypeName<"a">; // "string"
type T2 = TypeName<true>; // "boolean"
type T3 = TypeName<() => void>; // "function"
type T4 = TypeName<string[]>; // "object"
interface Person {
name: string;
age: number;
location: string;
}
type P1 = Person["name"]; // string
type P2 = string[][0]; // string
type P3 = string[]["length"]; // number
type P4 = [string]["length"]; // 1
type P5 = [string, string]["length"]; // 2
// Awaiting promises
type Awaited<T> =
T extends null | undefined ? T :
T extends PromiseLike<infer U> ? Awaited<U> :
T;
type P1 = Awaited<Promise<string>>; // string
type P2 = Awaited<Promise<Promise<string>>>; // string
type P3 = Awaited<Promise<string | Promise<Promise<number> | undefined>>; // string | number | undefined
// Flattening arrays
type Flatten<T extends readonly unknown[]> = T extends unknown[] ? _Flatten<T>[] : readonly _Flatten<T>[];
type _Flatten<T> = T extends readonly (infer U)[] ? _Flatten<U> : T;
type InfiniteArray<T> = InfiniteArray<T>[];
type A1 = Flatten<string[][][]>; // string[]
type A2 = Flatten<string[][] | readonly (number[] | boolean[][])[]>; // string[] | readonly (number | boolean)[]
type A3 = Flatten<InfiniteArray<string>>;
type A4 = A3[0]; // Infinite depth error
// Repeating tuples
type TupleOf<T, N extends number> = N extends N ? number extends N ? T[] : _TupleOf<T, N, []> : never;
type _TupleOf<T, N extends number, R extends unknown[]> = R['length'] extends N ? R : _TupleOf<T, N, [T, ...R]>;
type T1 = TupleOf<string, 3>; // [string, string, string]
type T2 = TupleOf<number, 0 | 2 | 4>; // [] | [number, number] | [number, number, number, number]
type T3 = TupleOf<number, number>; // number[]
type T4 = TupleOf<number, 100>; // Depth error
// Variadic tuple elements
type Foo<T extends unknown[]> = [string, ...T, number];
type T1 = Foo<[boolean]>; // [string, boolean, number]
type T2 = Foo<[number, number]>; // [string, number, number, number]
type T3 = Foo<[]>; // [string, number]
// Strongly typed tuple concatenation
function concat<T extends unknown[], U extends unknown[]>(t: [...T], u: [...U]): [...T, ...U] {
return [...t, ...u];
}
const ns = [0, 1, 2, 3]; // number[]
const t1 = concat([1, 2], ['hello']); // [number, number, string]
const t2 = concat([true], t1); // [boolean, number, number, string]
const t3 = concat([true], ns); // [boolean, ...number[]]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment