TS项目实践笔记
本文为在项目实际开发中的笔记沉淀
参考文章
ts演练场 https://www.typescriptlang.org/play
ts不是银弹: https://zhuanlan.zhihu.com/p/407711884
react官方ts文档: https://react.dev/learn/typescript
react ts cheatsheet https://react-typescript-cheatsheet.netlify.app/docs/basic/setup
and this: https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/basic_type_example
ruanyifeng: https://wangdoc.com/typescript/intro
如何学习?
- 学习文档、博客来学习TS基础
- 配合react ts官方文档
- ruanyifeng 文档
- 基于项目在实践中进行学习
- vue+ts
- react+ts
如何忽略ts检查
行内忽略
第1步: @ts-ignore
忽略下一行的ts检查
第2步: 禁用eslint (否则会出现 Do not use “@ts-ignore” because it alters compilation errors.)
// eslint-disable-next-line
// @ts-ignore
const a: object = 2; // 这里类型赋值不对,ts原本会提示报错
console.log('a: ', a);
忽略整个ts文件
在文件最顶部加上这段注释
// eslint-disable-next-line
// @ts-nocheck
行内忽略+全局eslint配置更改
由于有时候想忽略单行,但是又不想每次都加eslint忽略,想一行// @ts-ignore
就生效
第1步: 在eslintrc或者.eslintrc.cjs 添加配置 关闭
rules: {
"@typescript-eslint/ban-ts-comment": "off",
第2步: @ts-ignore
// @ts-ignore
const a: object = 2; // 这里类型赋值不对,ts原本会提示报错
console.log('a: ', a);
忽略eslint禁用any的规则
有时候项目会有Unexpected any. Specify a different type.
这往往是由于 .eslintrc.cjs 中的'plugin:@typescript-eslint/recommended',
导致
// 解决办法1
// eslint-disable-next-line
// 解决办法2
eslintrc.cjs添加一条规则:
"@typescript-eslint/no-explicit-any": ["off"],
断言与any
有时候我们在某些场景下明确知道某个值的类型或者不希望ts检查,就可以使用他们来进行规避。
断言
// as 断言的意思就是用户断定这是什么类型
type T = 'a'|'b'|'c';
let foo1 = 'a';
// const bar:T = foo1; // 这个报错,原因是父类型不能赋值给子类型(父类型更宽泛 它是string 子类型是常量)
// 我们可以改为
const bar:T = foo1 as T
any
any类型很宽泛,接受任何类型的赋值(它也能赋值给任何类型,污染变量,unknown类型不会污染)
let foo1 = 'a';
let bar:any = foo1
bar = 2 //不报错
React与TS结合
推荐查看react ts cheatsheet https://react-typescript-cheatsheet.netlify.app/docs/basic/setup
组件
类型主要源自 @types/react 和 @types/react-dom
function MyButton({ title }: { title: string }) {
return (
<button>{title}</button>
);
}
// 更多的是提取为接口
interface MyButtonProps {
title: string,
disabled: boolean
}
function MyButton({ title }:MyButtonProps) {
return (
<button>{title}</button>
);
}
// React.ReactNode 与 React.ReactElement区别?
React.ReactNode指任意类型,包含数字、字符串、null等;而React.ReactElement不包含,它只能是jsx;
interface MyComponentProps {
style: React.CSSProperties; //行内样式
}
hooks
const [enabled, setEnabled] = useState<boolean>(false);
// 联合类型
type RequestState =
| { status: 'idle' }
| { status: 'loading' }
| { status: 'success', data: any }
| { status: 'error', error: Error };
dom事件
// 这个回调函数类型是 React.ChangeEventHandler<HTMLInputElement>
const handleChange = useCallback<React.ChangeEventHandler<HTMLInputElement>>((event) => {
setValue(event.currentTarget.value);
}, [setValue])
<input value={value} onChange={handleChange} />
// 这个事件类型是 React.ChangeEvent<HTMLInputElement>
function handleChange(event: React.ChangeEvent<HTMLInputElement>) {
setValue(event.currentTarget.value);
}
<input value={value} onChange={handleChange} />
一些理解
父子类型赋值
子类型能赋值给父类型, 反之则不行: 如果类型 B 可以赋值给类型 A,TypeScript 就认为 B 是 A 的子类型(subtyping),A 是 B 的父类型。子类型满足父类型的所有结构特征,同时还具有自己的特征。凡是可以使用父类型的地方,都可以使用子类型,即子类型兼容父类型。
const B = {x: 1, y: 1}
const A: {x: number} = B // 通过检查
const C: {x: number,y: number,z: number,} = B // 报错 Property 'z' is missing in type
void 和undefined的区别
在js中undefined原本是在window上的一个属性,在低版本浏览器可以被重写;而在高版本浏览器中,它如果是局部变量就也能被重写。所以一般三方库用void 0
来替代undefined并且更简洁节省字节大小。
而在TS中:
void
用于函数的返回值类型,表示没有返回值。undefined
表示变量值未被赋值,也可用于声明变量的类型。
void 不能用于声明变量或对象属性的类型,只能用于函数的返回值类型。
如何基于后端数据快速生成interface
- json: 开源库生成对应的ts https://transform.tools/json-to-typescript
- 后端数据的话,有node工具(参考开源自己实现),可以直接根据接口文档生成对应的请求方法,ts都是写好的;这么做的话,就对后端要求比较高了,因为函数入参都是根据接口文档生成的
实用代码片段
枚举-基于value获取key
const getKeyByValue = function (value: string): string | undefined {
const foundEntry = Object.entries(LevelProps).find(([key, val]) => val === value);
return foundEntry ? foundEntry[0] : undefined;
};
配置项
打开编译选项strictNullChecks
这个选项默认为false,是关闭了null和undefined校验的
// 为false时
let bar = undefined // 会被断言为any类型
let foo1 = 'a';
foo1 = undefined // 能通过
foo1 = null // 能通过
// 为true时
let bar = undefined // 仍然会被断言为any类型
let foo1 = 'a';
foo1 = undefined // 报错
foo1 = null // 报错
对象严格字面量检查
编译器选项suppressExcessPropertyErrors
,可以关闭多余属性检查