Typescript Practice

125 阅读2分钟

精读《type challenges - easy》

Pick

Pick<Template,props1 | props2>,get a new type of object only contain specific properties

here is my answer

type MyPick<Target extends Object, SelectedProperties extends keyof Target> = {
    [key in SelectedProperties]: Target[key]
}

interface Todo {
  title: string
  description: string
  completed: boolean
}

type TodoPreview = MyPick<Todo, 'title' | 'completed'>

const todo: TodoPreview = {
    title: 'Clean room',
    completed: false,
}

Readonly & Partial

same as the test above,

interface Todo {
    title: string
    description: string
}
type MyReadonly<Target extends Object> = {
    readonly [key in keyof Target]: Target[key]
}
type Mypartial<Target extends Object> = {
	  [key in keyof Target]? : Target[key]
}

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

First of Array

maybe infer ?

type arr1 = ['a', 'b', 'c']
type arr2 = [3, 2, 1]

type First<Target> = Target extends [infer R, ...unknown[]] ? R : never

type head1 = First<arr1> // expected to be 'a'
type head2 = First<arr2> // expected to be 3

it seems I always get the complex answer rather than simpler one

the simpler ones

// simpler one
type First<T extends any[]> = T[0]

type First<T extends any[]> = T extends [] ? never : T[0]
type First<T extends any[]> = T['length'] extends 0 ? never : T[0]
type First<T> = T extends [infer P, ...infer Rest] ? P : never

Length

maybe just return the property ‘length’ ?

type tesla = ['tesla', 'model 3', 'model X', 'model Y']
type spaceX = ['FALCON 9', 'FALCON HEAVY', 'DRAGON', 'STARSHIP', 'HUMAN SPACEFLIGHT']

// my answer
type Length<T> = T extends { length: number } ? T['length'] : never

// the author`s answer
type Length<T extends any[]> = T['length']

type teslaLength = Length<tesla>  // expected 4
type spaceXLength = Length<spaceX> // expected 5

so far so good.just get it on !

Exclude

I guess it is a not or ‘~’ .(A few minutes later ~ ) It failed 💔

I just tried to get all the keys of Target and minus the specific ones. But just don`t know how to do it

here is the answer

type Exclude<T, U> = T extends U ? never : T

just get the wrong question… maybe i am thinking about Omit

As the author said ,the union type in typescript do like this below .but still can not figure out why is it

Exclude<'a'|'b','a'|'b'>
// equals to

Exclude<'a','a'|'c'> | Exclude<'b','a'|'c'>

By now , I just know how to get my problem fixed

interface Todo {
    title: string
    description: string
    completed: boolean
}
type HisExclude<T, U> = T extends U ? never : T

type MyExclude<T extends Object, props extends keyof T> = {
		// this get wrong
          // key in ((keyof T) extends props ? never : (keyof T))]: T[key]
		// this get right
		// should be no difference
		[key in HisExclude<keyof T, props>]: T[key]
}

type TodoPreview = MyExclude<Todo, 'title' | 'completed'>

const todo: TodoPreview = {
    description: "this"
}

Await

get type from Promise, looks like infer could help. Here is my answer

type Await<T> = T extends Promise<infer R> ? R : never

const value: Await<Promise<string>> = "string"

Promise may be recursive, so the author`s anwer is as below

type MyAwaited<T extends Promise<unknown>> = T extends Promise<infer P>
  ? P extends Promise<unknown> ? MyAwaited<P> : P
  : never

If

sorry , I just see the anwer without having a deep though…

So just do it with extends. 😊

type A = If<true, 'a', 'b'>  // expected to be 'a'
type B = If<false, 'a', 'b'> // expected to be 'b'
type If<Condition extends boolean, A, B> = Condition extends true ? A : B

Concat

looks a little difficult ? maybe ‘…’ ?

amazing! It works!

type Result = Concat<[1], [2]> // expected to be [1, 2]

type Concat<First extends unknown[], Second extends unknown[]> =
    [...First, ...Second]

The author give a better answer which consider situation given element that is not array

type Concat<P, Q> = [  ...P extends any[] ? P : [P],
  ...Q extends any[] ? Q : [Q],
]

Include

maybe extends or & ?, The key is to get the element type of array

By searching the Internet, it reminded me that I can get the type by T[number]. Ok, no question now!

type isPillarMen = Includes<['Kars', 'Esidisi', 'Wamuu', 'Dio'], 'Dio'> // expected to be `false`
type Includes<T extends unknown[], P> = P extends T[number] ? true : false

The author propose another question

type isPillarMen = Includes<[boolean], false> 
// true, but should be a false

true and false are both extends from boolean, that is the reason

So a exact equal should help

the rest of Include is coming soon ,I haven`t figure it out …

Push

things get easier now, just use ‘…’ like concat

type Result = Push<[1, 2], '3'> // [1, 2, '3']
type Push<T extends unknown[], K> = [...T, K]

Unshift

same as Push

type Result = Unshift<[1, 2], 0> // [0, 1, 2,]
type Unshift<T extends unknown[], K> = [K,...T]

Parameters

I think the answer is infer (True)

type MyParameters<T> = T extends (...args: infer R) => unknown ? R : never

type paras=MyParameters<(str: string, num: number) => boolean>

That is the end!

For me ,I can handle a few by myself, some by searching the internet, only two or three question I can`t fix up. The question Include is the most changeling for me. By now ,I haven`t figure out why 😒

Learnt the extends in typescript is an assignment, which makes it hard to understand