前言:怎么忍心怪你犯了错,是我给你自由过了火--张信哲
"tsconfigRootDir": "./",
注意
TS常用类型:
Number, String, Boolean, Null, Undefined,Symbol,bigInt:同js
6、元组:已知元素数量和类型的数组
7、枚举:一些带名字的常量
8、object:对象类型
9、Void:函数没有return
10、Never:不存在
11、unknow:未知类型
12、泛型:不特定数据类型
13、Any:任意值
声明为空值 void 的变量,只能被赋值为 null 和 undefined,比如: let unusable: void = undefined;
undefined 和 null 可以赋值给 任意类型 的数据,而 void 不可以
let num: number = undefined; // 不报错
let num: number = void; // 报错
一、ts 特殊符号用法
- 属性或参数中使用 ?.:表示该属性或参数为可选项
- 属性或参数中使用 !.:表示强制解析(告诉typescript编译器,这里一定有值),常用于vue-decorator中的@Prop
- 变量后使用 !:表示类型推断排除null、undefined
- 联合类型 A|B 表示只能选择满足形如A或者形如B
- 交叉类型 A&B 表示可以获取所有类型的所有属性名,赋值的时候需要满足所有类型的结构
注意,当交叉的类型中含有相同属性名但属性类型不一样的情况,该属性会成为never类型
- keyof 可以获取一个类型所有键值,返回一个联合类型
- ts常用声明类型
type ReactText = string | number;
type ReactChild = ReactElement | ReactText;
type ReactFragment = {} | ReactNodeArray;
type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;
interface ReactNodeArray extends Array<ReactNode> {}
interface ReactElement<P = any, T extends string | JSXElementConstructor<any> = string | JSXElementConstructor<any>> {
type: T;
props: P;
key: Key | null;
}
type Person = {
name: string;
age: number;
}
type PersonKey = keyof Person; // PersonKey得到的类型为 'name' | 'age'
//返回枚举类型
enumFilter: <T>(enumName: T, key: string): Partial<T> => {
const tempEnumName = { ...enumName };
const result: Partial<T> = {};
(Object.keys(tempEnumName) as (keyof T)[]).forEach((item) => {
if (key.indexOf(item as string) > -1) {
result[item] = tempEnumName[item];
}
});
return result;
},
//删除不需要的枚举类型
enumFilterNoEnum: <T>(enumName: T, key: string): Partial<T> => {
const tempEnumName = { ...enumName };
const newKey = key ? _.split(key, ',') : null;
if (newKey && newKey.length > 0) {
(newKey as (keyof T)[]).forEach((item) => {
delete tempEnumName[item];
});
}
return tempEnumName;
},
7.typeof 是获取一个对象/实例的类型,如下:
可以用类型声明替换,特殊情况需要omit或者继承一部分其他属性
const me: Person = { name: 'gzx', age: 16 };
type P = typeof me; // { name: string, age: number | undefined }
const you: typeof me = { name: 'mabaoguo', age: 69 } // 可以通过编译
二、Typescript 接口
1函数、可索引、类型接口
——————————————————————————————————————————————————————————————————————————————————
// 可索引接口 对数组的约束
interface UserArr { // 对数组的约束
[index:number]:string
}
// var arr:UserArr = ['aaa','bbb'];
var arr:UserArr = [123,'bbb']; /*错误*/
——————————————————————————————————————————————————————————————————————————————————
// 可索引接口 对对象的约束
interface UserObj {
[index:string]:string
}
2接口扩展、接口继承
// 接口扩展:接口可以继承接口 Person同时有Animaleat的和自己的work属性
interface Animal {
eat():void;
}
interface Person extends Animal {
work():void;
}
3interface与Type区别
interface只能表示function,object和class类型, type除了这些类型还可以表示其他类型,
interface A{name:string;
add:()=>void;
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
}
interface B{():void}
type C=()=>number;
type D=string;
type E={name:string,age:number}
interface可以继承interface,继承type,使用extends关键字 type也可继承type,也可继承interface,使用&
interface A{name:string}
interface B extends A{age:number}
type C={sex:string}
interface D extends C{name:string}
type E={name:string}&C
type F ={age:number}&A
类可以实现接口,也可以实现type
interface A{name:string;add:()=>void}
type B={age:number,add:()=>void}
class C implements A{
name:'xx'
add(){console.log('类实现接口')}
}
class D implements B{
age:20
add(){console.log('类实现type')}
}
三、泛型
T表示泛型,支持不特定的数据类型,具体什么类型是调用的时候决定的
泛型就是解决:函数、接口、类的复用性、以及对不特定数据类型的支持(类型校验)
1泛型定义(基本)
1、基本
function getData<T>(value:T):T{ // 这样就可以同时处理多套数据类型,防止冗余
return value;
}
getData<number>(123); //可以不指定number,类型推论可以直接推出来
getData<number, string>(1, '2') //泛型指定了第一个参数是数字,第二个参数是字符串,所以对应的参数也要这么传
//上例中,我们在函数名后添加了 <T>,其中 T 用来指代任意输入的类型,在后面的输入 value: T 和输出<T> 中即可使用了
2、数组
function getArr<T>(arr: T[]) {
return arr;
}
getArr<number>([1, 2, 3]) //指定了number,那我的数组必须每一项也是number,如果不是就报错
getArr<string>(['g', 'q', 'f']) //同理这里指定了string
3、获取对象对应key的value,使用obj[key]
function getVal<T>(obj: T, k: keyof T){
return obj[k];
}
interface Person {
name: string;
age: number;
}
getVal<Person>({
name: 'gqf',
age: 29
}, 'age') // 这里的key值只能传name或者age,否则就会报错,这个就是泛型的力量
2泛型接口(常用)
interface ConfigFn<T>{
(value:T):T;
}
function getData<T>(value:T):T{
return value;
}
var myGetData:ConfigFn<string> = getData; //确定了myGetData数据类型为string
myGetData('20'); /*正确*/
// myGetData(20) // 错误
3泛型约束(常用)
// 定义一个函数,接受两个参数:第一个是个对象 obj,第二个参数key是第一参数里面的键名, 需要输入obj[key]
function getProperty<T, K extends keyof T>(obj: T, key: K) {
return obj[key]
}
let obj = { a: 1, b: 2, c: 3 }
getProperty(obj, 'a') // success
getProperty(obj, 'm') // err obj 中不存在 m 这个参数
4泛型参数的默认类型
// 实际值参数中也无法推测出类型参数
function createArr<T = string>(length: number, value: T): Array<T> {
let result: T[] = []
for( let i = 0; i < length; i++ ) {
result[i] = value
}
return result
}
四、类型断言
语法§:值 as 类型
1、将一个联合类型断言为其中一个类型§
interface Cat {
name: string;
run(): void;
}
interface Fish {
name: string;
swim(): void;
}
function isFish(animal: Cat | Fish) {
if (typeof (animal as Fish).swim === 'function') { //断言animal是fish
return true;
}
return false;
}
五、映射类型
1、Partial(常用)将每个属性转换为可选属性
type Partial<T> = {
[P in keyof T]?: T[P];
}
type PersonPartial = Partial<Person>;
// ^ = type PersonPartial = {
// name?: string | undefined;
// age?: number | undefined;
// }
2、Omit(常用)适用于键值对对象的Exclude,去除类型中包含的键值对
interface Todo {
title: string;
description: string;
completed: boolean;
}
type TodoPreview = Omit<Todo, "description">;
const todo: TodoPreview = {
title: "Clean room",
completed: false,
};
3、Record<K, T> 常用
此工具的作用是将 K 中所有属性值转化为 T 类型,我们常用它来申明一个普通 object 对象。
type Record<K extends keyof any,T> = {
[key in K]: T
}
这里特别说明一下,keyof any对应的类型为number | string |symbol,也就是可以做对象键(专业说法叫索引 index)的类型集合。 举个例子:
const obj: Record<string, string> = { 'name': 'mbg', 'tag': '年轻人不讲武德' }
4、Pick选取一组属性指定新类型
此工具的作用是将 T 类型中的 K 键列表提取出来,生成新的子键值对类型。
type Pick<T, K extends keyof T> = {
[P in K]: T[P]
}
const bird: Pick<Animal, "name" | "age"> = { name: 'bird', age: 1 }
5、Exclude去除交集,返回剩余的部分
此工具是在 T 类型中,去除 T 类型和 U 类型的交集,返回剩余的部分。
type Exclude<T, U> = T extends U ? never : T
type T1 = Exclude<"a" | "b" | "c", "a" | "b">; // "c"
type T2 = Exclude<string | number | (() => void), Function>; // string | number
6、ReturnType获取返回值类型,一般为函数
7、Nullable转换为旧类型和null的联合类型
8、Readonly将每个属性转换为只读属性
9、Required将每个属性转换为必选属性
六、常用定义
1、数组
// 1
let arr3: Array<any> = [1, 2, 'hh']
// 2
export const tabRecordConfig: {
list: MenuType[];
list2: string[];
cacheKey: string;
onDelete?: (item: MenuType) => void; //函数
} = {
list: Cache.getItem(cacheKey) || [],
cacheKey,
onDelete: () => null,
};
// 3
export interface ArrType {
[index: string]: string | number | [];
}
2、对象
/** 对象数组 常用 */
objArr: {
id: string;
title: string;
}[];
/** key 可以为任意 string,值限制为 MyTypeHere 类型 */
dict1: {
[key: string]: MyTypeHere;
};
dict2: Record<string, MyTypeHere>; // 基本上和 dict1 相同,用了 TS 内置的 Record 类型。
export type BillGoodsInfo={}
export type BillGoodsInfoType = Partial<BillGoodsInfo>; //变成可选项
3、函数
/** 没有参数的函数 不需要返回值 常用 */
onClick: () => void;
/** 带函数的参数 非常常用 */
onChange: (id: number) => void;
/** 另一种函数语法 参数是 React 的按钮事件 � 非常常用 */
onClick(event: React.MouseEvent<HTMLButtonElement>): void;
/** 一般返回值的写法(不推荐),多数采用泛型*/
type Func = (param: number) => number;
const func: Func = (param: number) => param * 2;
4、React 相关类型
export declare interface AppProps {
children: React.ReactNode; // 包含所有 children 情况
functionChildren: (name: string) => React.ReactNode; // 返回 React 节点的函数
// 也可以在泛型的位置传入组件 提取组件的 Props 类型
props: React.ComponentProps<"button">;
// 推荐 利用上一步的做法 再进一步的提取出原生的 onClick 函数类型
// 此时函数的第一个参数会自动推断为 React 的点击事件类型
onClickButton:React.ComponentProps<"button">["onClick"]
}
七、React--hooks项目使用
利用 React.FC 内置类型的话,不光会包含你定义的 AppProps 还会自动加上一个 children 类型,以及其他组件上会出现的类型
interface AppProps = { message: string };
const App: React.FC<AppProps> = ({ message, children }) => {
return (
<>
{children}
<div>{message}</div>
</>
)
};
useState
- 1、如果你的默认值已经可以说明类型,那么不用手动声明类型,交给 TS 自动推断即可:
// val: boolean
const [val, toggle] = React.useState(false);
- 2、自定义
const [loading, setLoading] = useState<string>('');
useRef
声明返回对象中 current 属性的类型
function TextInputWithFocusButton() {
const inputEl = React.useRef<HTMLInputElement>(null); //定义
const onButtonClick = () => {
if (inputEl && inputEl.current) {
inputEl.current?.focus(); //使用
}
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
useReducer
需要用 Discriminated Unions 来标注 Action 的类型。
const initialState = { //初始值
count: 0
};
type ACTIONTYPE =
| { type: "increment"; payload: number }
| { type: "decrement"; payload: string };
function reducer(state: typeof initialState, action: ACTIONTYPE) {
switch (action.type) {
case "increment":
return { count: state.count + action.payload };
case "decrement":
return { count: state.count - Number(action.payload) };
default:
return state;
}
}
function Counter() {
const [state, dispatch] = React.useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({ type: "decrement", payload: "5" })}>
-
</button>
<button onClick={() => dispatch({ type: "increment", payload: 5 })}>
+
</button>
</>
);
}