上面这个是今天会提到的内容,如果你已经可以轻松看懂,欢迎直接左转去看我队友们的精彩文章!
昨天我们已经学到了 Mapped Types 的精华,就是可以在 Index Signatures 中使用 in
来叠代 in
後面的所有元素,便可以透过 Mapped Type 修改物件型别中所有属性值的型别。因此,可以把原本的 SupportedEvent
进行修改:
type SupportedEvent = {
click: string;
change: string;
keyup: string;
keydown: string;
};
透过 HandledEvent
这个 Utility Type 进行转换後,产生出新的型别:
type HandledEvent = {
[K in keyof SupportedEvent]: () => void;
};
更好的方式还可以把 Supported Event
变成一个泛型的参数,让它变成 Utility Type,像是这样,如此 MappedValuesToFunction
就可以变的更泛用:
type MappedValuesToFunction<T> = {
[K in keyof T]: () => void;
};
type HandledEvent = MappedValueToFunction<SupportedEvent>;
从昨天的内容中,我们已经知道如何透过 Mapped Types 「一次修改所有 SupportedEvent
属性值的型别」,最後得到的 HandledEvent
会是:
type HandledEvent = {
click: () => void;
change: () => void;
keyup: () => void;
keydown: () => void;
};
如果现在我们不是要修改物件型别中属性值的型别,而是想要修改属性 key 的名称时,可以怎麽做呢?举例来说,我们想要根据 HandledEvent
,透过某个 Utility Type 後可以产生出像这样的型别:
type EventHandler = {
handleClick: () => void;
handleChange: () => void;
handleKeyup: () => void;
handleKeydown: () => void;
};
这时候就可以用到今天要提的这个 Utility Type:
让我们来依序拆解并理解这个写法。
首先,从 in
这个关键字可以看到这里用了 Mapped Type,而 [K in keyof T]
的意思就是把 T
这个物件型别的所有 key 取出组成 union types,以这里来说,如果写 ToEventHandler<HandledEvent>
的话,这里的 keyof T
应该就会变成 "click" | "change" | "keyup" | "keydown"
:
所以说 [K in keyof T]
就会是用叠代的方式,每次取出 "click" | "change" | "keyup" | "keydown"
中的元素来跑回圈,可以想像组出来的东西应该会像这样:
type HandledEvent = {
click: '...';
change: '...';
keyup: '...';
keydown: '...';
};
接着我们看到这里有 Template Literal 的用法,也就是 `${}`
的用法,并且搭配关键字 as
来使用:
透过 as
後面接字串型别的方式,就可以让我们达到修改属性 key
的目的。
现在为了方便理解,我们先把 Template Literal 中的 Capitalize
拿掉:
type ToEventHandler<T> = {
[K in keyof T as `handle${string & K}`]: T[K];
};
这时候应该会看到经过这个 Utility Type 後跑出来的型别会是:
type EventHandler = ToEventHandler<HandledEvent>;
// 预期 EventHandler 会长这样
type EventHandler = {
handleclick: '...';
handlechange: '...';
handlekeyup: '...';
handlekeydown: '...';
};
这里我们已经成功透过 Mapped Type 搭配 as
和 Literal Template 的使用,成功把物件型别的 key 进行了转换,让每个 key 的最前面都多了 handle...
的前缀。
但因为在 JavaScript 中,通常函式的命名会用小写驼峰的方式,例如,handleClick
、handleChange
,因此这里可以在搭配使用在 Day12 时曾经提到的 Intrinsic String Manipulation Types ,透过 Capitalize
来将字串型别的第一个字转成英文大写,因此如果改会原本的写法 as `handle${Capitalize<string & K>}`
後,产生出来的 key 的名称就会是我们想要的以 handle
作为开头的 key:
type EventHandler = ToEventHandler<HandledEvent>;
// 预期 EventHandler 会长这样
type EventHandler = {
handleClick: '...';
handleChange: '...';
handleKeyup: '...';
handleKeydown: '...';
};
来看最後一个部分:
这里我们把 Mapped Types 跑回圈是的变数取名为 K
,而不论取名是 K
或 P
,它都只是个变数名称,要取名成什麽都可以,但实际上它也不单单只是个名称,它还可以被拿来被後续使用。
这里 [...]: T[K]
中 :
後面放的就是这个属性值的型别,我们知道 T
就是我们带进去的物件型别,而 K
其实就是没有次跑回圈时的 key
,因此 T[K]
就是我们在 Day05 曾提过的 Indexed Access Types,意思就是直接把该属性值原本的型别取出来就好。
现在总结来看,应该就可以知道怎麽透过 Mapped Type 搭配 as
和 Template Literal 来修改物件型别中的属性名称:
type SupportedEvent = {
click: string;
change: string;
keyup: string;
keydown: string;
};
type MappedValuesToFunction<T> = {
[K in keyof T]: () => void;
};
type HandledEvent = MappedValuesToFunction<SupportedEvent>;
type ToEventHandler<T> = {
[K in keyof T as `handle${Capitalize<string & K>}`]: T[K];
};
type EventHandler = ToEventHandler<HandledEvent>;
这里最终的 EventHandler
就会是:
type EventHandler = {
handleClick: () => void;
handleChange: () => void;
handleKeyup: () => void;
handleKeydown: () => void;
};
https://tsplay.dev/mAVZRW @ TypeScript Playground
<<: 【Day 15】- 今天来实作一个 Kernel mode Thread
>>: 2.4.6 Design System - Carousel
Optimizer 优化器 神经网路是由多个神经元节点组成,每个神经元(Neuron)都拥有自己的权...
其实今年才刚学Vue.js ,目前的程度大概就是写几个简单的功能而已,要写一个比较完整的网站还是十分...
改变path的样貌 首先观看以下程序码 const width = 800; const heigh...
今日题目 题目连结:605. Can Place Flowers 题目主题:Array, Greed...
前面有提到Raspberry pi有网路的功能 既然有网路 就可以将感测器所计算出来的数据 传送到云...