理论学习
类型推断
类型推断分为 基础类型推断、联合类型推断、上下文类型推断
// 基础类型推断
let a = 1; //推断为number
let 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; // error
b = a; // error
c = a; // error
c = 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);
}
<textarea
ref={textRef}
value={input}
placeholder="请输入内容…"
onChange={handleInputChange} />
// 正确的写法1
<textarea
ref={textRef}
value={input}
placeholder="请输入内容…"
onChange={(e) => setInput(e.target.value)} />
// 正确的写法2
const [input, setInput] = useState('');
const handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
setInput(e.target.value);
}
<textarea
ref={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)
自己只有一些推断,还无法给到解释。