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)