0%

Type-Challenges

Type-Challenges

这里记录一些基于type-challenges的一些挑战题目来学习的typescript type笔记

背景

1
2
3
4
5
6
7
8
9
10
11
12
13
// 以下这三个类型均来源于 '@type-challenges/utils' 这些类型将会在接下来用于判断挑战的结果。这里简单介绍以下这三个类型 
import { Equal, Expect, NotAny } from '@type-challenges/utils'
// Expect 是一个泛型 接受一个参数 类型T 类型T要继承自true即类型T要为true否则会报错 如此就实现了判断类型是不是true的方法。
type Expect<T extends true> = T
// 这个可化繁一下
// export type Equals<X, Y> =
// (<T>() => T extends X ? 1 : 2) extends
// (<T>() => T extends Y ? 1 : 2) ? true : false;
// 这里做了个延迟判断
// 简单来说就是 Ts本身在给定X,Y之前无法确定T类型就延迟判断, 给定X,Y了之后(<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2)整理要为true即T同时具有X和Y的属性,如果T不同时具有X和Y的属性即整体为false。这样就是延迟判断。
type Equal<X, Y> = <T>() => T extends X ? 1 : 2 extends <T>() => T extends Y ? 1 : 2 ? true : false
// 做了一个简单的判断 T 为any类型的话会报错
type NotAny<T> = true extends IsAny<T> ? false : true

Hello World

[挑战地址](https://www.typescriptlang.org/play?# code/PQKgUABBCMDMEFoIAkCmAbdB7CB1LATugCaSIIWVkBGAnhAIIB2ALgBZZP0BiArhAAoAAgENWAM14BKCAGJAtw6BquIhkys9REAZGYDu3VVDSYsAGjyESAQj0RAm-GAqOUAB3oFVlQCFugBeNAd6mAYPUDY5oErowAbygPfKgKdygNf6gPgJgFBygNJGEAAqtAAOqBAAwmwimKhMAOaoAM6AQAyAFOrWgDOJgDD-gIhGgDdygP7ygBSugGFygABygNlygHqegOKazoABRoDnur7xSagAygDGBACWiSwQgFgJgOPxgFeBis6A3j6A0eqA3z6A+36ApuaAedqADc7LgBVKgCRKmoUqUGSltoCIxoAYRoC0chX+gADpgIGRgHfygJymgGg5QCdps5AMdygEAPOqAdP1ANK2gFXopaACH+6oA3RUAhTaASHMtoBMVMA99GASH-ClYAAZklj5MjAYAQQD45t5APRmLVsEHyLGmuQgWzILBGKAw2HwRGIEAAvBAxLQyGSSaTyZSoNSIF9vjDAEGagOsgBkIwCwcoAseUA2UaAL8VAED6gA49Hl8lgFObigCiAA9kuMWAAeO0AR14mVdBkFZmIJjZHJyAD5Q9KyVZAJ0OgG-FSKgiAkwClxoB15ReJIggAB9QDTmoA0fwhgEB-wCjpoAUBMAkIahQtWUMQYoQADiU3YvGoEEigFPzQDQ7oAsf7YLBYiXyAC5qRTxmwAHQAK3yk8IOWAcGAAC82AhUgA5MAgYBgfegCAAfRPp7Pp+V4Ihx-Pt6PEF3+95yX5hiFJDFEq4ECVqCdqBdVARRYHBqBSERWXZKZcn3MBDzvW8IARBpAGj5G8EIvR8pgAW0SQg5gAbwgT1vXQExHWdFgTE3LAWGYegAF8IHEAgsGwiAAHIhGfVAEAnTJ0GyPJ8mAXgWCmdB8g4p8+XGER8gKT8AG0yAogC3RouiuF9AUsHfYhwyMVT-xdd0vR9P09IDIMoNycMwAAXVguCQHQjD70BFpAFNrNyMIfPdQDIWtADAlQBquX8ZxAGPIwAVbz7Ach1HYBxynWd5wIRdlzEfIAHdUAIVd1y3IKIG7GK4sHEcx3yCcZznBcl1gYB8iwdAxKmTgFQgWtABezQAsTR0cqEqqmrUvqtcN23R8wCAA)

1
2
3
4
// 期望是一个 string 类型
type HelloWorld = any
// 你需要使得如下这行不会抛出异常
type test = Expect<Equal<HelloWorld, string>>

答案

1
2
3
4
// 期望是一个 string 类型
type HelloWorld = string
// 你需要使得如下这行不会抛出异常
type test = Expect<Equal<HelloWorld, string>>

解释

如题就是一个Hello World。题目要求HelloWorld的类型是string。

直接在定义处给string即可

type HelloWorld = string

知识点

这个hello world只需要读懂type test = Expect<Equal<HelloWorld, string>>即可。

Pick

[挑战地址](https://www.typescriptlang.org/play# code/PQKgUABBAsELQUHnagG5wgBQJYGMDWl5yFH4BGAnhAIIB2ALgBYD21FAYgK4QAUAAgIZ0AZuwCUEAMSAA70CqyhPbUMzCSXYYANrTgZq+fOP0RAGRmA7t11QAfBECMroHYYwDLWgK8DAFUqBv-0CL0YBh-wETWgOfj0AJQhATlNAbfj3QApYwHnEwCAGMwhAA9NAAHTAf3lACldAUMVAO39AELcAA0xcAB4AFQAaCABpc1zAbZtAaPVAZ2VAe+VYqHxALATAcfjAOblcitzAWjlASATAS6NAPR1AcgNc4tzAU3NAEPNAAgTAbx86uMBo+UAgzTjc3doAZ3xtWgBTACdBPiwTiGLGABNGCABvfChaDFo1E4AuCH3aGdtABzN4Qe4nfZYIEABw+zD+AKB1FBUCgWEYAFsYd9Tvc-iRGIxvgJ8ABfOK0Mgwm53R5oM4nABuGBOAHcIABeCAAWTIBRwJQejHKAHIPl8TqKIAAfCCijHY3Ene6i8xxDHUAEQWjCv50xgM5msjnc15otES75-UUAYRJ1AgZyJmNFpTB6KxOJOeL+lzU+xO7qgFKgu1ycUsgAp1CAAcU+9HYJAggCg5QCn5oBod0AWP-0Wi0GH7H7AYAHLD0AB0ACt9uXGGdgcBoMAAF70OC2gByYBAwDAfdAEAA+sOR6ORxBAAby2UAx3KAQA8h2PF4OID2+1Sabz+dhBWVKpZuQIyH2wAOl4uIIBpW0Aq9GpdYLs-j1cYbF12gvCAAUQAjuw+Gpyh+AAeNJYG+ZIQIIzqYvKPDriccBln+3wopCwDsB8Aaimu1I3FgfCBvsXIQAA2vgQEgbQhTfr+ahUcBJygSqACM5R8gKQqPGKVpSuYvHBp+9GgVRP5-nRFEqgATKxW5FAaXGfN80pygqXrKqqvHmPxxYQLB+xwCcgmaOczpnPgbHbhxIrytxSnyoq3p4rZoraEyf4YOp7oALp9sc5yXNctzCi8+DcYigIgvgEJQrC8LUGFyKohA9lqQSRIOmAFJgL5FxXDc5EMXiTHBe8Cm-P84UohlPl0H5uUCeJ9wScVOqlfFEWekqPoqqlxInKSmX9iA94PsugDQcoAAHKAKbWw0PiuvagPgliAGBKgDVclOgDHkYAKt45nmBZFiWUIVtWtb1o2wACPsbLnC2badotECZltO35oWxalkdNZ1g2Tb7MS6GKFq92AC9mgBYmiYz17W9h1Vp9p2tu2XarmAQA)

1
2
3
4
5
6
7
8
9
10
11
12
13
// 通过从K中选择属性T来构造类型
interface Todo {
title: string
description: string
completed: boolean
}

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

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

答案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/* _____________ 你的代码 _____________ */
type MyPick<T extends object, K extends keyof T> = {[P in K]:T[P]};


/* _____________ 测试用例 _____________ */
import { Equal, Expect } from '@type-challenges/utils'

type cases = [
Expect<Equal<Expected1, MyPick<Todo, 'title'>>>,
Expect<Equal<Expected2, MyPick<Todo, 'title' | 'completed'>>>,
// @ts-expect-error
MyPick<Todo, 'title' | 'completed' | 'invalid'>,
]

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

interface Expected1 {
title: string
}

interface Expected2 {
title: string
completed: boolean
}

解释

首先由题意得MyPick接受了两个类型Todo即是要从该类型中提取属性,另一个类型即Todo中所具有的属性。所以MyPick本身接受的类型不难构建type MyPick<T extends object, K extends keyof T> 接下来要做的操作即从遍历给出的K中所有的属性,并从T中返回这些属性的类型即可。[P in K]即遍历K中的值即输入的T中的属性,T[P]即从T中拿到给出的属性的类型。

知识点

keyof关键字

TypeScript 允许我们遍历某种类型的属性,并通过 keyof 操作符提取其属性的名称。**keyof 操作符是在 TypeScript 2.1 版本引入的,该操作符可以用于获取某种类型的所有键,其返回类型是联合类型。**

1
2
3
4
5
6
7
8
9
interface Person {
name: string;
age: number;
location: string;
}

type K1 = keyof Person; // "name" | "age" | "location"
type K2 = keyof Person[]; // number | "length" | "push" | "concat" | ...
type K3 = keyof { [x: string]: Person }; // string | number

In关键字

In关键字遍历给出的类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 在此示例中,将从该类型中取出所有属性,并将其值更改为布尔。
type OptionsFlags<Type> = {
[Property in keyof Type]: boolean;
};

type FeatureFlags = {
darkMode: () => void;
newUserProfile: () => void;
};

type FeatureOptions = OptionsFlags<FeatureFlags>;

type FeatureOptions = {
darkMode: boolean;
newUserProfile: boolean;
}

参考 & 引用

[Feature request]type level equal operator · Issue # 27024 · microsoft/TypeScript (github.com)

TypeScript居然还能这么玩 - 知乎 (zhihu.com)

TypeScript: Documentation - TypeScript 2.1 (typescriptlang.org)