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
// error
log(textHash[code]);
}
if (ErrorCodes.A === code || ErrorCodes.B === code) {
// normal
log(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);
//error
dispatch(row);
// way1
if (row) {
dispatch(row);
}
// way2
dispatch(row!);
const matched = prependList.find(row => row.type === rowType);
//error
dispatch([...matched, ...state]]
// right
dispatch([...(matched ? matched : []), ...state]]
const row = list.find(d => d.id === rowId);
// error
row.count += 1; // 如果类型设定count为optional
// right
row.count! += 1; // 如果类型设定count为optional,通过明确告知我知道它就是数字类型
// error
const { id, type } = rowData; //如果rowData类型推断为可能为undefined
2.3 在2.2中体现了两种做法,一种明确知道它就是有值的,因此更多的用!
断言,还有一种则是通过三元运算符?
或if
写更多的防御性代码.
2.4 useRef 结合 ant design的 TextArea 组件,无法给到满意的声明,
const inputRef = useRef<HTMLTextAreaElement>(null);
<TextArea
// error
ref={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)
简单总结:
- 函数的实现少传递参数、不声明类型是可以兼容的;
- 多传递参数、指明明显不同的类型是不可以兼容的。