1. noImplicitlyAny
1.1 类型没有明确定义
enum ErrorCodes {A = 'A',B = 'B',C = 'C',}const textHash = {A: 'error a',B: 'error b',};function log(text: string) {console.log(text);}function print(code: ErrorCodes) {if ([ErrorCodes.A, ErrorCodes.B].includes(code)) {// textHash[code] 类型可能是 any// 因为code的key可能有A B C,而实际数据中只有A B两个key// 当code为C的时候,匹配的类型不能被确定,也就是当做了any// errorlog(textHash[code]);}if (ErrorCodes.A === code || ErrorCodes.B === code) {// normallog(textHash[code]);}}
1.2 如果useReducer中声明了state和action的类型,但是action后续来的数据没有明确定义类型,会导致使用staet的数据结构也编程不能确定,因此action中数据必须明确,更新到state中的也必须匹配。另外比较好的做法是default中也进行state的返回?
1.3 如果定义了更宽泛,实际使用更子集的类型是没问题的
1.4 泛型的使用例子
参考 泛型可以用在函数上,首先定义函数的接口,然后定义函数的实现,最后调用时候传入真实类型
interface CreateArrayFunc {<T>(length: number, value: T): Array<T>;}let createArray: CreateArrayFunc;createArray = function<T>(length: number, value: T): Array<T> {let result: T[] = [];for (let i = 0; i < length; i++) {result[i] = value;}return result;}createArray(3, 'x'); // ['x', 'x', 'x']
问题中泛型接口明确了它期望接收React.MouseEvent并且具体的泛型类型为HtmlImageElement和Event
interface MouseEvent<T = Element, E = NativeMouseEvent> extends UIEvent<T, E> {altKey: boolean;button: number;buttons: number;clientX: number;clientY: number;ctrlKey: boolean;/*** 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.*/getModifierState(key: string): boolean;metaKey: boolean;movementX: number;movementY: number;pageX: number;pageY: number;relatedTarget: EventTarget | null;screenX: number;screenY: number;shiftKey: boolean;}
2. strictNullChecks
2.1 useState中声明的状态如何进行初始化,似乎比较合理的做法是不进行初始化,而在使用的地方进行判断
2.2 在不能明确判断是否为符合要求的类型时
大量使用?,在链式调用属性时,可能存在undefined,因此要使用类似 下面这样的写法state.data?.list?.find(row => row.id === id)
大量使用!或 if判断,如果结果不确切能找到结果的前提下,需要保证给到确切的数据结构
cons row = list.find(row => row.id === id);//errordispatch(row);// way1if (row) {dispatch(row);}// way2dispatch(row!);const matched = prependList.find(row => row.type === rowType);//errordispatch([...matched, ...state]]// rightdispatch([...(matched ? matched : []), ...state]]const row = list.find(d => d.id === rowId);// errorrow.count += 1; // 如果类型设定count为optional// rightrow.count! += 1; // 如果类型设定count为optional,通过明确告知我知道它就是数字类型// errorconst { id, type } = rowData; //如果rowData类型推断为可能为undefined
2.3 在2.2中体现了两种做法,一种明确知道它就是有值的,因此更多的用!断言,还有一种则是通过三元运算符?或if写更多的防御性代码.
2.4 useRef 结合 ant design的 TextArea 组件,无法给到满意的声明,

const inputRef = useRef<HTMLTextAreaElement>(null);<TextArea// errorref={inputRef}value={reply?.content}onChange={(e) => {if (reply) {setReply({...reply,content: e,});}}}maxLength={200}style={{ '--font-size': '0.24rem' }}autoSize={{ minRows: 3, maxRows: 10 }}placeholder={reply?.type === ReplyType.COMMENT ? `回复${reply.name}:` : '友善评论的人运气都不会太差:'}/>
3. Others
3.1 排除策略
关于函数类型不兼容的问题,通过编辑器的提示,可以非常准确地定位到问题,初看下图信息很多找不到重点
拷贝提示信息出来后可以最终定位到原因是data.list的结构声明的不对
Type '(params: ParamsType & { pageSize?: number | undefined; current?: number | undefined; keyword?: string | undefined; }) => Promise<{ success: true; data: BannedAccount[][]; total: number; }>' is not assignable to type'(params: ParamsType & { pageSize?: number | undefined; current?: number | undefined; keyword?: string | undefined; }, sort: Record<string, SortOrder>, filter: Record<...>) => Promise<...>'.Type 'Promise<{ success: true; data: BannedAccount[][]; total: number; }>' is not assignable to type 'Promise<Partial<RequestData<BannedAccount>>>'.Type '{ success: true; data: BANNED.BannedAccount[][]; total: number; }' is not assignable to type 'Partial<RequestData<BannedAccount>>'.Types of property 'data' are incompatible.Type 'BannedAccount[][]' is not assignable to type 'BannedAccount[]'.Type 'BannedAccount[]' is missing the following properties from type 'BannedAccount': id, knightId, knightName, bannedStart, and 6 more.ts(2322)
另外隐含了一个信息,即接口实现和声明参数结构可以不一样,如下为代码和错误提示:
function test(func: (a:number, b:number) => number) {}test((a) => a)test((a:string) => a)test((a, b, c) => a + b + c)

简单总结:
- 函数的实现少传递参数、不声明类型是可以兼容的;
- 多传递参数、指明明显不同的类型是不可以兼容的。

