获取函数的返回值类型
我们现在有一个简单的函数fn:
const fn = (a: string, b: number) => {
return `${a}-${b}`
}
现在想获取到fn函数的返回值类型,用作其他操作。我们可以使用Typescript内置的工具泛型Returntype
type FnReturnType = ReturnType<typeof fn>;
获取函数的参数类型
如果我又想知道fn函数的第一个参数a的类型,可以使用Parameters
type FnParametersType = Parameters<typeof fn>;
type AType = FnParametersType[0]
上面FnParametersType存的是一个Tuple,也就是一个元组,我们通过取第一个元素来获取参数a的类型。
获取Promise包裹的类型
我们有一个async函数,它返回一个对象,最终会被Promise包裹。
const getUser = async () => {
return {
id: 1,
name: 'zhaomeicheng',
gender: 'male'
}
}
我们想得到最终return的对象的类型,但是有讨厌的Promise泛型存在,类似于Promise<{ id: number, name: string, gender: string}> 这时可以使用Awaited
type User = Awaited<ReturnType<typeof getUser>>
这里的Awaited就好像我们JavaScript里await promise,最终会把promise的成功值给到等号的右边一样
获取对象的属性组成的联合类型
假设我现在有一个对象如下:
const obj = {
prop1: {},
prop2: {},
prop3: {},
};
我希望可以得到prop1 | prop2 | prop3,这里面就要用到keyof了!
type Keys = keyof typeof obj;
函数throw an error,怎么就never了。
function alwaysError(): never {
throw new Error('here is an error')
}
never是Typescript类型系统里的Bottom Type,中文翻译过来就是“从不”的意思,但是为什么上面代码的返回类型是never而不是void呢? 我个人理解,never可以理解标注事情不会到达,因为这个函数抛出错误导致函数永远不会有返回值,所以使用never。
关于never的用户,就是用来做兜底检查的,我们有一个函数,参数可能为string或者number,但是如果有一天,别人扩展出了boolean,却没有针对boolean情况进行处理,这不是我们想要的,利用never可以进行检查报错。
const fn = (arg: string | number) => {
if (typeof arg === 'string') {
} else if (typeof arg === 'number') {
} else {
const neverValue: never = arg;
}
}
如果后续别人给arg加了别的类型,但是几乎任何类型的值赋值给never,都会报错。这样就达到了代码可维护的目的。
TSconfig中有一个配置项叫做StrictNullChecks,默认是关闭的。 在这种上下文中,undefined和null是几乎任何类型的子类型,也就是说我可以把undefined和null赋值给任何变量:
let str: string;
let num: number;
str = null;
str = undefined;
num = null
num = undefined;
但是这样很容易存在问题,假设我有一个函数,接收person对象,读取person的name属性,然后输出:
const sayName = (person: { name: string }) => {
console.log(person.name)
}
sayName(null)
sayName(undefined)
上面代码TS并不会提示报错,然而在runtime执行时,尝试读取null/undefined的属性,会导致程序崩溃。 但是一旦开启了strictNullchecks以后,undefined和null不再属于任何一个集合,也意味着再讲null和undefined赋值给任何变量,TS都不再允许。
sortByKey (泛型练习)
function sortByKey<T> (data: T[], key: keyof T) {
data.sort((pre, next) => {
if (pre[key] > next[key]) return 1;
if (pre[key] < next[key]) return -1;
return 0;
})
}
keyof能够获取到一个interface的所有key组成的联合类型,很好用。
映射类型 mapped type
type MyPick<T, U extends keyof T> {
[K in U]: T[K]
}
interface Example {
a: string;
b: number;
c: boolean;
}
type Picked = MyPick<Example, 'a' | 'b'>
如果我们有一个组件Button,希望在点击的时候,进行事件的上报,我们会在Button的onClick props里,上报。
const App = () => {
const logging = () => console.log('logging');
const hanldeClick = () => {}
const onClick = () => {
logging();
hanldeClick();
}
return <Button onClick={onClick}></Button>
}
现在,希望每一个整个APP内的每个Button组件都要上报,所以我们不得不把上报逻辑写进Button组件内部的实现里:
const Button = () => {
const logging = () => console.log('logging');
const hanldeClick = () => {}
const onClick = () => {
logging();
hanldeClick();
}
return <button onClick={onClick} />
}
但是我们现在不止要在Button组件里实现上报逻辑,我们要在ListItem组件内,实现一样的上报逻辑:
const ListItem = () => {
const logging = () => console.log('logging');
const hanldeClick = () => {}
const onClick = () => {
logging();
hanldeClick();
}
return <div onClick={onClick} />
}
这样实现起来不优雅,我们在复制-粘贴代码。可以使用高阶组件把逻辑抽象出来,像这样
const withLogging = (Component) => {
return (props) => {
const logging = () => console.log('logging');
const onClick = () => {
logging();
// 重点在这里,一定要调用props.onClick()。
props.onClick();
}
return <Component {...props} onClick={onClick}/>
}
}
之后我们的使用就很简单了:
const ListItemWithLogging = withLogging(ListItem)
const ButtonWithLogging = withLogging(Button)
这样的好处是,我们没有「入侵」我们的业务组件了!而是enhance组件的功能!相同的逻辑我们只写在了一处,方便维护。
Markdown is powered by Markdoc. This is an example post to demonstrate all the basic markdown syntax. You can author content using the familiar markdown syntax you already know.
Inline formatting
Bold: This text is bold.
Italics: This text is italics.
Strikethrough: You can strikethrough text.
Inline code: You can add inline code like this const hello = "world".
Headings
The following HTML <h2>—<h6> elements represent five levels of section headings. <h1> is also available but not recommended since the post title is already a <h1> element it is not a good practice to have more than one <h1> elements in a page.
H2: Heading Two
H3: Heading Three
H4: Heading Four
H5: Heading Five
H6: Heading Six
Paragraph
A standalone single paragraph of text.
Paragraphs can be multiline too when they constitute words that make up more than one line, i.e they wrap to the next line. Wow! I am really smart to write two lines of text that makes zero sense.
Blockquotes
This is a blockquote. And it's pretty long too. Long enough to wrap to next line. Surely it will wrap.
You can use other Markdown syntax like
inline codewithin a blockquote.
Tables
| Italics | Bold | Code |
|---|---|---|
| italics | bold | code |
List Types
Ordered List
- First item
- Second item
- Third item
Unordered List
- List item
- Another item
- And another item
Nested list
- Fruit
- Apple
- Orange
- Banana
- Dairy
- Milk
- Cheese
Code Blocks
Syntax highlighting is done using Prism.js. You can customise to whichever theme you want from the plenty available prism themes.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Example HTML5 Document</title>
</head>
<body>
<p>Test</p>
</body>
</html>
Images
