1. noImplicitlyAny

1.1 类型没有明确定义

  1. enum ErrorCodes {
  2. A = 'A',
  3. B = 'B',
  4. C = 'C',
  5. }
  6. const textHash = {
  7. A: 'error a',
  8. B: 'error b',
  9. };
  10. function log(text: string) {
  11. console.log(text);
  12. }
  13. function print(code: ErrorCodes) {
  14. if ([ErrorCodes.A, ErrorCodes.B].includes(code)) {
  15. // textHash[code] 类型可能是 any
  16. // 因为code的key可能有A B C,而实际数据中只有A B两个key
  17. // 当code为C的时候,匹配的类型不能被确定,也就是当做了any
  18. // error
  19. log(textHash[code]);
  20. }
  21. if (ErrorCodes.A === code || ErrorCodes.B === code) {
  22. // normal
  23. log(textHash[code]);
  24. }
  25. }

image.png


1.2 如果useReducer中声明了state和action的类型,但是action后续来的数据没有明确定义类型,会导致使用staet的数据结构也编程不能确定,因此action中数据必须明确,更新到state中的也必须匹配。另外比较好的做法是default中也进行state的返回?

1.3 如果定义了更宽泛,实际使用更子集的类型是没问题的

1.4 泛型的使用例子
image.png
参考 泛型可以用在函数上,首先定义函数的接口,然后定义函数的实现,最后调用时候传入真实类型

  1. interface CreateArrayFunc {
  2. <T>(length: number, value: T): Array<T>;
  3. }
  4. let createArray: CreateArrayFunc;
  5. createArray = function<T>(length: number, value: T): Array<T> {
  6. let result: T[] = [];
  7. for (let i = 0; i < length; i++) {
  8. result[i] = value;
  9. }
  10. return result;
  11. }
  12. createArray(3, 'x'); // ['x', 'x', 'x']

问题中泛型接口明确了它期望接收React.MouseEvent并且具体的泛型类型为HtmlImageElement和Event

  1. interface MouseEvent<T = Element, E = NativeMouseEvent> extends UIEvent<T, E> {
  2. altKey: boolean;
  3. button: number;
  4. buttons: number;
  5. clientX: number;
  6. clientY: number;
  7. ctrlKey: boolean;
  8. /**
  9. * See [DOM Level 3 Events spec](https://www.w3.org/TR/uievents-key/#keys-modifier). for a list of valid (case-sensitive) arguments to this method.
  10. */
  11. getModifierState(key: string): boolean;
  12. metaKey: boolean;
  13. movementX: number;
  14. movementY: number;
  15. pageX: number;
  16. pageY: number;
  17. relatedTarget: EventTarget | null;
  18. screenX: number;
  19. screenY: number;
  20. shiftKey: boolean;
  21. }

2. strictNullChecks

2.1 useState中声明的状态如何进行初始化,似乎比较合理的做法是不进行初始化,而在使用的地方进行判断

2.2 在不能明确判断是否为符合要求的类型时

大量使用?,在链式调用属性时,可能存在undefined,因此要使用类似 下面这样的写法
state.data?.list?.find(row => row.id === id)

大量使用if判断,如果结果不确切能找到结果的前提下,需要保证给到确切的数据结构

  1. cons row = list.find(row => row.id === id);
  2. //error
  3. dispatch(row);
  4. // way1
  5. if (row) {
  6. dispatch(row);
  7. }
  8. // way2
  9. dispatch(row!);
  10. const matched = prependList.find(row => row.type === rowType);
  11. //error
  12. dispatch([...matched, ...state]]
  13. // right
  14. dispatch([...(matched ? matched : []), ...state]]
  15. const row = list.find(d => d.id === rowId);
  16. // error
  17. row.count += 1; // 如果类型设定count为optional
  18. // right
  19. row.count! += 1; // 如果类型设定count为optional,通过明确告知我知道它就是数字类型
  20. // error
  21. const { id, type } = rowData; //如果rowData类型推断为可能为undefined

2.3 在2.2中体现了两种做法,一种明确知道它就是有值的,因此更多的用!断言,还有一种则是通过三元运算符?if写更多的防御性代码.

2.4 useRef 结合 ant design的 TextArea 组件,无法给到满意的声明,

image.png

  1. const inputRef = useRef<HTMLTextAreaElement>(null);
  2. <TextArea
  3. // error
  4. ref={inputRef}
  5. value={reply?.content}
  6. onChange={(e) => {
  7. if (reply) {
  8. setReply({
  9. ...reply,
  10. content: e,
  11. });
  12. }
  13. }}
  14. maxLength={200}
  15. style={{ '--font-size': '0.24rem' }}
  16. autoSize={{ minRows: 3, maxRows: 10 }}
  17. placeholder={reply?.type === ReplyType.COMMENT ? `回复${reply.name}:` : '友善评论的人运气都不会太差:'}
  18. />

3. Others

3.1 排除策略

关于函数类型不兼容的问题,通过编辑器的提示,可以非常准确地定位到问题,初看下图信息很多找不到重点
image.png
拷贝提示信息出来后可以最终定位到原因是data.list的结构声明的不对

  1. Type '(params: ParamsType & { pageSize?: number | undefined; current?: number | undefined; keyword?: string | undefined; }) => Promise<{ success: true; data: BannedAccount[][]; total: number; }>' is not assignable to type
  2. '(params: ParamsType & { pageSize?: number | undefined; current?: number | undefined; keyword?: string | undefined; }, sort: Record<string, SortOrder>, filter: Record<...>) => Promise<...>'.
  3. Type 'Promise<{ success: true; data: BannedAccount[][]; total: number; }>' is not assignable to type 'Promise<Partial<RequestData<BannedAccount>>>'.
  4. Type '{ success: true; data: BANNED.BannedAccount[][]; total: number; }' is not assignable to type 'Partial<RequestData<BannedAccount>>'.
  5. Types of property 'data' are incompatible.
  6. Type 'BannedAccount[][]' is not assignable to type 'BannedAccount[]'.
  7. Type 'BannedAccount[]' is missing the following properties from type 'BannedAccount': id, knightId, knightName, bannedStart, and 6 more.ts(2322)

另外隐含了一个信息,即接口实现和声明参数结构可以不一样,如下为代码和错误提示:

  1. function test(func: (a:number, b:number) => number) {
  2. }
  3. test((a) => a)
  4. test((a:string) => a)
  5. test((a, b, c) => a + b + c)

image.png
简单总结:

  1. 函数的实现少传递参数、不声明类型是可以兼容的;
  2. 多传递参数、指明明显不同的类型是不可以兼容的。