理论学习
类型推断
类型推断分为 基础类型推断、联合类型推断、上下文类型推断
// 基础类型推断let a = 1; //推断为numberlet add = (value = 1) => value + 1; // 推断参数和返回值是number// 联合类型推断let b = [1, 'abc']; //推断为number和string的联合类型// 上下文类型推断window.onkeydown = (event) => {console.log(event.button); // 推断为键盘事件,因为没有button,所以会报错}
类型断言,当你对自己的代码比TS对类型推断更自信时,可以明确指定类型,但注意不能滥用。下面是几个例子:
interface Foo {id: number}//报错let foo = {}foo.id = 1001;//Property 'id' does not exist on type '{}'.console.log(foo.id);//Property 'id' does not exist on type '{}'.console.log((foo as Foo).id);//right//正常let foo: Foo = {id: 1001}console.log(foo.id);
interface Note {id?: number}function deleteNote(id:number) {console.log(id);}let note:Note = {id: 123}//报错deleteNote(note.id); //Argument of type 'number | undefined' is not assignable to parameter of type 'number'.Type 'undefined' is not assignable to type 'number'.deleteNote(note.id as number); // 类型断言为number
类型兼容
// 接口兼容性interface X {a: any;b: any;}interface Y {a: any;b: any;c: any;}let x: X = {a: 1, b: 2};let y: Y = {a: 1, b: 2, c: 3};x = y;y = x; // Property 'c' is missing in type 'X' but required in type 'Y'.// 函数兼容性type Handler = (a: number, b: number) => void;function hof(handler: Handler) {return handler;}// 1) 参数个数let handler1 = (a: number) => {}hof(handler1);let handler2 = (a: number, b: number, c: number) => {};hof(handler2); // Argument of type '(a: number, b: number, c: number) => void' is not assignable to parameter of type 'Handler'.ts(2345)// 可选参数和剩余参数let a = (p1: number, p2: number) => {}let b = (p1?: number, p2?: number) => {}let c = (...args: number[]) => {}a = b;a = c;b = c; // errorb = a; // errorc = a; // errorc = b; // error// 2)参数类型let handler3 = (a: string) => {}hof(handler3); //Argument of type '(a: string) => void' is not assignable to parameter of type 'Handler'.interface Point3D {x: number;y: number;z: number;}interface Point2D {x: number;y: number;}let p3d = (point: Point3D) => {};let p2d = (point: Point2D) => {}p3d = p2d;p2d = p3d; // Type '(point: Point3D) => void' is not assignable to type '(point: Point2D) => void'.// 3)返回值类型let f = () => ({name: 'Alice'})let g = () => ({name: 'Alice', location: 'shanghai'});f = g;g = f; // Type '() => { name: string; }' is not assignable to type '() => { name: string; location: string; }'.function overload(a: number): number;function overload(a: string): string;function overload(a: any): any {// 前两个是声明,第三个是实现,并且应该是更宽的类型,否则会报错}// 枚举兼容性enum Fruit { Apple }let fruit: Fruit.Apple = 3;let no: number = Fruit.Apple;enum Color { Red }let color: Color.Red = Fruit.Apple; // Type 'Fruit' is not assignable to type 'Color'.// 类的兼容性class A {constructor(p: number, q: number) {}id = 1;// private name = ''; // 增加此行(私有属性)后 a = b 报错}class B {static s = 1;constructor(p: number) {}id = 2;}let a = new A(1, 2);let b= new B(2);a = b; // 可以比较,因为静态成员和构造函数不参与比较,实例成员id做比较b = a; // 同上class C extends A {}let cc = new C(1, 2);aa = cc; // 继承的类可以兼容cc = aa; // 同上// 泛型兼容性interface Empty<T> {value: T; // 如果不增加T的具体使用,那么是可以相互兼容的}let obj1: Empty<number> = { value: 1 };let obj2: Empty<string> = { value: '1'};obj1 = obj2; // Type 'Empty<string>' is not assignable to type 'Empty<number>'.let log1 = <T>(x: T): T => {return x}let log2 = <U>(y: U): U => {return y}log1 = log2
类型保护
lang因为是联合类型(JavaScript|Java),在分支判定中,各种使用了类型断言,代码比较冗余
enum Type {Strong,Weak}class Java {java: any;helloJava() {console.log('hello java');}}class JavaScript {javascript: any;helloJavaScript() {console.log('hello javascript');}}function isJava(lang: Java | JavaScript): lang is Java {return (lang as Java).helloJava !== undefined;}function getLanguage(type: Type, x: string | number) {let lang = (type === Type.Weak) ? new JavaScript() : new Java();if ((lang as JavaScript).helloJavaScript) {(lang as JavaScript).helloJavaScript();} else {(lang as Java).helloJava();}return lang;}getLanguage(Type.Strong);
为了让TS能识别类型,有几种实现方法
- instanceof
- in ( 这里特意引入了两个属性,分别是两个类特有)
- typeof 这里引入了第二个参数(抛开lang来讲解类型识别)
- isJava引入了一个判定方法,注意语法 ```json function isJava(lang: Java | JavaScript): lang is Java { return (lang as Java).helloJava !== undefined; }
function getLanguage(type: Type, x: string | number) { // instanceof if (lang instanceof Java) { lang.helloJava(); } else { lang.helloJavaScript(); }
//in if (‘java’ in lang) { lang.helloJava(); } else { lang.helloJavaScript(); }
// typeof if (typeof x === ‘string’) { x.length } else { x.toFixed(2); }
// 类型判断方法 if (isJava(lang)) { lang.helloJava() } else { lang.helloJavaScript(); }
return lang; }
<a name="j4ajV"></a>## 直接传递函数导致上下文丢失```javascript// 错误的写法const [input, setInput] = useState('');const handleInputChange = (e) => { //Parameter 'e' implicitly has an 'any' type.setInput(e.target.value);}<textarearef={textRef}value={input}placeholder="请输入内容…"onChange={handleInputChange} />
// 正确的写法1<textarearef={textRef}value={input}placeholder="请输入内容…"onChange={(e) => setInput(e.target.value)} />// 正确的写法2const [input, setInput] = useState('');const handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {setInput(e.target.value);}<textarearef={textRef}value={input}placeholder="请输入内容…"onChange={handleInputChange} />
useState未正确指明类型导致的报错
错误的写法
const [ noteList, setNoteList ] = useState<>([]);setNoteList((prevList) => [ note, ...prevList ])
Argument of type ‘(prevList: never[]) => Note[]’ is not assignable to parameter of type ‘SetStateAction
正确的写法(指定了类型)
const [ noteList, setNoteList ] = useState<Note[]>([]);setNoteList((prevList) => [ note, ...prevList ])
IndexedDB进行插入操作报错
对于primary key,如果id为undefined是会报错的,需要删除无用id值
useRef创建的HTMLTextAreaElement对象报错
问题描述
const textRef = useRef<HTMLTextAreaElement>()<textarea ref={textRef} placeholder="请输入内容…"/>
Type ‘MutableRefObject
解决办法
const textRef = useRef<HTMLTextAreaElement>(null)
自己只有一些推断,还无法给到解释。

