0x00 What are we gonna do
const fib = (n: number): number => (n <= 1 ? n : fib(n - 1) + fib(n - 2));
for (let i = 0; i < 10; i++) {
console.log(i, fib(i));
}
Copy the code
Remember, remember (° °) Blue ✿
However, this is what we really want to do ↓↓↓, which is use TS Type to solve FIbonacci
import { Fib, Add } from "./fib-type";
type one = Fib<1>;
type zero = Fib<0>;
type Two = Add<one, one>;
type Five = Add<Two, Add<Two, one>>;
type Fib5 = Fib<Five>;
type Fib9 = Fib<9>;
type r0 = Fib<Zero>; // type r0= 0
type r1 = Fib<One>; // type r1 = 1
type r2 = Fib<Two>; // type r2 = 1
type r3 = Fib<3>; // type r3 = 2
type r4 = Fib<4>; // type r4 = 3
type r5 = Fib<5>; // type r5 = 5
type r6 = Fib<6>; // type r6 = 8
type r9 = Fib<9>; // type r9 = 34
type sum = Add<r9, r6>; // type sum = 42
Copy the code
1×00 What do we do
Fib has basic comparison, addition, and looping, so we need to use the type system to do that in turn
1 x01 addition
To implement addition, you need to implement some tool types first
Type Length<T extends any[]> = T[" Length "]; type Length<T extends any[]> = T[" Length "]; type one = 1; Type a111 = 0 extends one? true : false; // type a111 = false type a112 = 1 extends one ? true : false; // type a112 = trueCopy the code
The implementation of range is recursive
function range(n, list = []) {
if (n <= 0) return list.length;
return range(n - 1, [1, ...list]);
}
Copy the code
Ts constraint, no loops, you have to use recursion instead of loops, and we’ll see a couple of things like that later, but remember, recursion has a few exits, an object has a few keys, and each key is a condition
Type Range<T extends Number = 0, P extends any[] = []> = {0: Range<T, [any,...P]>; 1: P; }[Length<P> extends T ? 1 : 0]; Type Concat<T extends any[], P extends any[]> = [...T,...P]; type t1 = Range<3>; // type t1 = [any, any, any] type Zero = Length<Range<0>>; // type Zero = 0 type Ten = Length<Range<10>>; // type Ten = 10 type Five = Length<Range<5>>; // type Five = 5 type One = Length<Range<1>>;Copy the code
Adding is easier by finding the length of the union of the two elements
type Add<T extends number, P extends number> = Length<
Concat<Range<T>, Range<P>>
>;
type Two = Add<One, One>;
// type Two = 2
type Three = Add<One, Two>;
// type Three = 3
Copy the code
But how do you do subtraction? Subtraction and division are generally harder than addition, so we need more tools
1×02 comparison function
Some tool types
-
Shift: Deletes the first element
-
Append: Inserts an element at the end of a tuple
-
IsEmpty/NotEmpty: determines that the list IsEmpty
/ / remove yuan group of the first element [1, 2, 3] – > [2, 3] type Shift extends < T any [] > = ((… t: T) => any) extends ( _: any, … Shift: infer P ) => any ? P : [];
type pp = Shift<[number, boolean, string, Object]>; // type pp = [Boolean, string, Object] // Appends type Append<T extends any[], E = any> = […T, E]; type IsEmpty<T extends any[]> = Length extends 0 ? true : false; type NotEmpty<T extends any[]> = IsEmpty extends true ? false : true; type t4 = IsEmpty<Range<0>>; // type t4 = true type t5 = IsEmpty<Range<1>>; // type t5 = false
Logic type
-
And: a && B
Type extends Boolean, P extends Boolean > = T extends false? false : P extends false ? false : true; type t6 = And<true, true>; // type t6 = true
type t7 = And<true, false>; // type t7 = false
type t8 = And<false, false>; // type t8 = false
type t9 = And<false, true>; // type t9 = false
Less than or equal to
Pseudo code:
function dfs(a, b) { if (a.length && b.length) { a.pop(); b.pop(); return dfs(a, b); } else if (a.length) { a >= b; } else if (b.length) { b > a; Type LessEqList<T extends any[], P extends any[]> = {0: <T extends any[] LessEqList<Shift<T>, Shift<P>>; 1: true; 2: false; }[And<NotEmpty<T>, NotEmpty<P>> extends true ? 0 : IsEmpty<T> extends true ? 1 : 2]; Type LessEq<T extends number, P extends number> = LessEqList< Range<T>, Range<P> >; type t10 = LessEq<Zero, One>; // type t10 = true type t11 = LessEq<One, Zero>; // type t11 = false type t12 = LessEq<One, One>; // type t12 = trueCopy the code
1 x03 subtraction
The list of subtraction
By default, I’m going to go big and I’m going to go small and I’m going to go big and I’m going to go the other way and I’m going to add a sign, but I didn’t do that for simplicity
// const a = [1, 2, 3]; const b = [4, 5]; const c = []; while (b.length ! == a.length) { a.pop(); c.push(1); }// c.length === a.length - b.lengthconsole.log(c.length); SubList<T extends any[]; SubList<T extends any[]; SubList<T extends any[]; P extends any[], R extends any[] = []> = { 0: Length<R>; 1: SubList<Shift<T>, P, Append<R>>; }[Length<T> extends Length<P> ? 0 : 1]; type t13 = SubList<Range<10>, Range<5>>; // type t13 = 5Copy the code
Digital subtraction
It’s just a tuple of numbers and a comparison
Type Sub<T extends number, P extends number> = {0: Sub<P, T>; 1: SubList<Range<T>, Range<P>>; }[LessEq<T, P> extends true ? 0 : 1]; type t14 = Sub<One, Zero>; // type t14 = 1 type t15 = Sub<Ten, Five>; // type t15 = 5Copy the code
Now that we have these tools, we can translate JS into TS
2×00 Fib: JS function –> TS
In JS, we use functions
const fib = (n: number): number => n <= 1 ? n : fib(n - 1) + fib(n - 2);
Copy the code
In TS, we use type, which is just another way of writing it
export type Fib<T extends number> = {
0: T;
1: Add<Fib<Sub<T, One>>, Fib<Sub<T, Two>>>;
}[LessEq<T, One> extends true ? 0 : 1];
type r0 = Fib<Zero>;
// type r10= 0
type r1 = Fib<One>;
// type r1 = 1
type r2 = Fib<Two>;
// type r2 = 1
type r3 = Fib<3>;
// type r3 = 2
type r4 = Fib<4>;
// type r4 = 3
type r5 = Fib<5>;
//type r5 = 5
type r6 = Fib<6>;
// type r6 = 8
Copy the code
I have a lot of fun ideas, but there’s too little dian square here to write, you know
Other fun
TypeScript type metaprogramming: Implements 8-digit arithmetic operations
What’s New in TypeScript 4.1: Is Vuex finally Ready for string templates?
advertising
Byte front end – educational direction, if you want to play can be pushed in
If there’s a fun job, you can take me… (A handyman, not a brick remover)