TS项目总结随记

388 阅读8分钟

前言:怎么忍心怪你犯了错,是我给你自由过了火--张信哲


"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 的变量,只能被赋值为 nullundefined,比如: let unusable: void = undefined;
undefinednull 可以赋值给 任意类型 的数据,而 void 不可以
let num: number = undefined; // 不报错
let num: number = void; // 报错

一、ts 特殊符号用法

  1. 属性或参数中使用 ?.:表示该属性或参数为可选项
  2. 属性或参数中使用 !.:表示强制解析(告诉typescript编译器,这里一定有值),常用于vue-decorator中的@Prop
  3. 变量后使用 !:表示类型推断排除null、undefined
  4. 联合类型 A|B 表示只能选择满足形如A或者形如B
  5. 交叉类型 A&B 表示可以获取所有类型的所有属性名,赋值的时候需要满足所有类型的结构

    注意,当交叉的类型中含有相同属性名但属性类型不一样的情况,该属性会成为never类型

  6. keyof 可以获取一个类型所有键值,返回一个联合类型
  7. 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>
    </>
  );
}