https://ts.xcatliu.com/basics/type-of-array
一个函数需要的参数是一个固定的结构
接口可以帮我们定义这种类型
接口规定数据类型的 可以是对象类型(参数类型) 也可以是类的类型 函数的类型 总之是用来定义类型的
interface b
简单理解 需要a:b (需要的参数a 是接口b这种类型的)
interface LabelledValue {
label: string;
}
function printLabel(labelledObj: LabelledValue) {
console.log(labelledObj.label);
}
let myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);
//需要注意的是 类型检查器不会去检查属性的顺序,只要相应的属性存在并且类型也是对的就可以。
//换句话说 传入的参数 只要包含接口定义的属性并且类型正确就可以了 不用管他在哪 以及多属性的前后顺序
有些时候我们不是一定要某些参数 而是在一定条件下要一些参数
interface SquareConfig {
color?: string;
width?: number;
}
function createSquare(config: SquareConfig): {color: string; area: number} {
let newSquare = {color: "white", area: 100};
if (config.color) {
newSquare.color = config.color;
}
if (config.width) {
newSquare.area = config.width * config.width;
}
return newSquare;
}
let mySquare = createSquare({color: "black"});
//加一个? 即可 成为可选属性
只读属性
interface Point {
readonly x: number;
readonly y: number;
}
//用 readonly 来定义 只读属性
//定义后
let p1: Point = { x: 10, y: 20 };
p1.x = 5; // error!
//数组只读 不可修改
let a: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray<number> = a; //ro是一个只读数组 他的值是数组a
ro[0] = 12; // error!
ro.push(5); // error!
ro.length = 100; // error!
a = ro; // error!
readonly
vs const
最简单判断该用readonly
还是const
的方法是看要把它做为变量使用还是做为一个属性。 做为变量使用的话用const
,若做为属性则使用readonly
。
额外的属性检查
如果一个对象字面量存在任何“目标类型”不包含的属性时,你会得到一个错误。
interface SquareConfig {
color?: string;
width?: number;
}
function createSquare(config: SquareConfig): { color: string; area: number } {
// ...
}
let mySquare = createSquare({ colour: "red", width: 100 });
// error: 'colour' not expected in type 'SquareConfig'
let mySquare = createSquare({ colour: "red", width: 100 });
//绕过ts的额外属性检查 最简单的方法 就是使用类型断言 可看官网文档
//最好的方法 添加一个字符串索引签名 不明白什么意思 没关系 直接看例子就能懂了
interface SquareConfig {
color?: string;
width?: number;
[propName: string]: any;
}
//在这我们要表示的是SquareConfig可以有任意数量的属性,并且只要它们不是color和width,那么就无所谓它们的类型是什么(类型 any)。
函数类型的接口
即定义一个函数的类型
interface SearchFunc {
(source: string, subString: string): boolean;
}
//()参数列表 (): 返回值类型
函数类型的类型检查来说,函数的参数名不需要与接口里定义的名字相匹配。 但是对应位置的参数类型一定要匹配
let mySearch: SearchFunc;
mySearch = function(src: string, sub: string): boolean {
let result = src.search(sub);
return result > -1;
}
//完全没问题
//但是如果 return 一个数字或者字符串 编译ts 就会报错 警告我们函数的返回值类型与 SearchFunc接口中的定义不匹配。
可索引的类型接口
//可索引类型具有一个 索引签名,它描述了对象索引的类型,还有相应的索引返回值类型。
interface StringArray {
[index: number]: string;
}
//[]定义索引类型 : 返回值
let myArray: StringArray;
myArray = ["Bob", "Fred"];
let myStr: string = myArray[0];
TypeScript支持两种索引签名:字符串和数字。 可以同时使用两种类型的索引,但是数字索引的返回值必须是字符串索引返回值类型的子类型。
class Animal {
name: string;
}
class Dog extends Animal {
breed: string;
}
// 错误:使用数值型的字符串索引,有时会得到完全不同的Animal!
interface NotOkay {
[x: number]: Animal;
[x: string]: Dog;
}
字符串索引签名 会确保所有属性与其返回值类型相匹配。
interface NumberDictionary {
[index: string]: number;
length: number; // 可以,length是number类型
name: string // 错误,`name`的类型与索引类型返回值的类型不匹配
}
可以将索引签名设置为只读,这样就防止了给索引赋值:
interface ReadonlyStringArray {
readonly [index: number]: string;
}
let myArray: ReadonlyStringArray = ["Alice", "Bob"];
myArray[2] = "Mallory"; // error!
类类型的接口
类使用接口的关键字implements
interface ClockInterface {
currentTime: Date;
setTime(d: Date);
}
class Clock implements ClockInterface {
currentTime: Date;
setTime(d: Date) {
this.currentTime = d;
}
constructor(h: number, m: number) { }
}
//类静态部分与实例部分的区别
interface ClockConstructor {
new (hour: number, minute: number);
}
class Clock implements ClockConstructor {
currentTime: Date;
constructor(h: number, m: number) { }
}
//会报错 这是因为只对其实例部分进行类型检查。 constructor存在于类的静态部分,所以不在检查的范围内。 所以实力部分并没有定义new(..)
如何设置类的静态解构:
interface claaA {
new(name: string, age: number);
}
interface classB {
con()
}
function creat(c: claaA, name: string, age: number): classB {
return new c(name, age);
}
class A implements classB {
constructor(name: string, age: number) { }
con() { console.log("123") }
}
let a = creat(A, "张三", 12)
//个人理解 类A 是参数c要符合claaA的类型 则有一个new() 构造函数 即有了constructor并且传入的值要一致