const getUserInfo = function (user) {
return `name: ${user.name}, age: ${user.age}`;
};
getUserInfo({ name: 'koala', age: 18 });
// 错误的调用
getUserInfo(); // Uncaught TypeError: Cannot read property 'name' of undefined
console.log(getUserInfo({ name: 'long' })); // name: long, age: undefined
getUserInfo({ name: 'long', height: 1.66 }); // name: long, age: undefined
const getUserInfo = (user: { name: string, age: number }): string => {
return `name: ${user.name} age: ${user.age}`;
};
getUserInfo({ name: 'long', age: 18 });
// 错误的调用
// getUserInfo(); // 错误信息:An argument for 'user' was not provided.
// getUserInfo({ name: 'long' }); // 错误信息:Property 'age' is missing in type '{ name: string; }'
// getUserInfo({ name: 'long', height: 1.88 }); // 错误信息:类型不匹配
// 先定义一个接口
interface IUser {
name: string;
age: number;
}
const getUserInfo = (user: IUser): string => {
return`name: ${user.name}, age: ${user.age}`;
};
// 正确的调用
getUserInfo({name: "long", age: 18});
type IUserInfoFunc = (user: IUser) =>string;
interface IUser {
name: string;
age: number;
}
const getUserInfo: IUserInfoFunc = (user) => {
return`name: ${user.name}, age: ${user.age}`;
};
getUserInfo({name: "koala", age: 18});
// getUserInfo();
// 接口的实现,使用 implements 关键字
interface Entity {
title: string;
log(): void;
}
class Post implements Entity {
title: string;
constructor(title: string) {
this.title = title;
}
log(): void {
console.log(this.title);
}
}
// 声明一个接口
interface IPerson {
name: string;
age: number;
}
// type类似interface,以下写法等同用interface声明IPerson
type IPerson {
name: string;
age: number;
}
class Person {
constructor(public config: IPerson) {
}
}
// 再调用时,要满足接口的要求(不能增加,也不能减少)
var p1 = new Person({
name: "张三";
age: 18
})
// interface 能够声明合并,Type不可以
interface User {
name: string
age: number
}
interface User {
sex: string
}
/*
User 接口为 {
name: string
age: number
sex: string
}
*/
interface Animal {
eat(food:string);
}
class Sheep implements Animal {
// 实现接口,必须要实现接口里的类
eat(food:string) {
console.log("wo chi cao");
}
}
interface Func {
(x: number, y: number, desc?: string): void
}
<=>
type Func = (x: number, y: number, desc?: string) =>void;
const sum: Func = function (x, y, desc = '') {
// const sum: Func = function (x: number, y: number, desc: string): void {
// ts类型系统默认推论可以不必书写上述类型定义
console.log(desc, x + y)
}
sum(32, 22)
// 定义函数
interface SearchFunc {
(source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
// 该函数拥有和类型声明一致的参数类型和返回值。
mySearch = function (source: string, subString: string) {
let result = source.search(subString);
return result > -1;
};
// 编译器会自动推断参数和返回值的类型
let mySearch: SearchFunc;
mySearch = function (src, sub) {
let result = src.search(sub);
return result > -1;
};
// 编译器推断返回值为 boolean 类型。
// 如果你返回了错误的类型,编译器会报错
let mySearch: SearchFunc;
mySearch = function (src, sub) {
// Type '(src: string, sub: string) => string' is not assignable to type 'SearchFunc'.
// Type 'string' is not assignable to type 'boolean'.
let result = src.search(sub);
return 'string';
};
insterface IPerson {
name: string;
age ?: number; // 可选属性
sex ?: '男' | '女' // IPerson可选一个sex属性,值为'男'或者'女'或者undefined}
[propName: string]: any; // 字符串类型的索引签名
}
let user: IPerson = {
name: 'mark',
age: 1,
work: 'web'
};
// 如果任意类型定义为string 那么 上面代码会报错。
insterface IPerson {
name: string;
age ?: number;
[propName: string]: string; //error TS2411: Property 'age' of type 'number' is not assignable to string index type 'string'
}
// 可选属性,使用,先进行判断后,进行使用
if (user.age) {
user.age
}
interface SquareConfig {
color?: string;
width?: number;
}
function createSquare(config: SquareConfig): { color: string; area: number } {
return { color: config.color || "red", area: config.width || 20 };
}
// let mySquare = createSquare({ colour: "red", width: 100 }); // 报错
// 报错原因
// TypeScript 认为这可能是一个 BUG。
// 编译器在将对象字面量赋值给别的变量或者传递给某个函数时会有一个被称为***多余属性检查***的特殊过程。
// 如果对象字面量有任何目标类型所没有的属性时,就会报错;
// Argument of type '{ colour: string; width: number; }' is not assignable to parameter of type 'SquareConfig'.
// Object literal may only specify known properties, but 'colour' does not exist in type 'SquareConfig'. Did you mean to write ‘color'
// 跳过该检查
// let mySquare = createSquare({ width: 100, opacity: 0.5 } as SquareConfig);
// 如果非要 增加额外属性
// 添加一个字符串类型的索引签名
interface SquareConfig {
color?: string;
width?: number;
[propName: string]: any;
}
// 接口除了可以给函数、对象声明类型,
// 还可以给任何有索引的对象声明类型,比如数组。
// 可索引的类型由索引签名来描述对象的类型
interface StringArray {
[index: number]: string;
}
// StringArray 拥有一个索引签名,这个签名的属性的类型是 number,而属性值的类型是 string
let myArray: StringArray;
myArray = ["Bob", "Fred"];
let myStr: string = myArray[0];
// 索引签名的属性的类型有两种,number 或者 string;
// 当然你可以同时支持两种类型,
// 但是使用数字来索引的属性的类型必须是使用字符串索引的类型的子类型,
// 因为 JavaScript 在索引的时候,
// 会将数字类型的属性转换为字符串类型。
// 这就意味着索引 100 的类型应该和索引 "100" 的一致
interface Animal {
name: string;
}
interface Dog extends Animal {
breed: string;
}
// Error: indexing with a numeric string might get you a completely separate type of Animal!
interface NotOkay {
// [x: number]: Animal;
// Numeric index type 'Animal' is not assignable to string index type 'Dog'.
[x: number]: Dog; // [x:number]:Dog , Dog 要和 Dog保持一致
[x: string]: Dog;
}
// 只读类型的 可索引类型
interface ReadonlyStringArray {
readonly [index: number]: string;
}
let myArray: ReadonlyStringArray = ['Alice', 'Bob'];
// myArray[2] = 'Mallory'; // error!
// Index signature in type 'ReadonlyStringArray' only permits reading.
interface IPerson {
readonly id: number;
name: string;
age?: number;
[index: number]: number; // 数组
family: Array // IPerson需要包含一个family属性,类型是数组,数组里面都是string类型的数据
[propName: string]: any;
}
let user: IPerson = {
id: 1,
name: 'mar;',
work: ‘web’,
family:[‘1’]
};
user.id = 2;
// 报错 Cannot assign to 'id' because it is a constant or a read-only property.
// 只读数组
let a: number[] = [1, 2, 3, 4];
let ro: Readonly Array = a;
// ro[0] = 12; // error!
// Index signature in type 'readonly number[]' only permits reading.
// ro.push(5); // error!
// Property 'push' does not exist on type 'readonly number[]'.
// ro.length = 100; // error!
// Cannot assign to 'length' because it is a read-only property.
// a = ro; // error!
// The type 'readonly number[]' is 'readonly' and cannot be assigned to the mutable type 'number[]'.
// 通过类型断言来跳过该问题
let a: number[] = [1, 2, 3, 4];
let ro: Readonly Array = a;
a = ro as number[];
interface ClockInterface {
currentTime: Date;
}
class Clock implements ClockInterface {
currentTime: Date = new Date();
constructor(h: number, m: number) {}
}
// 定义方法
interface ClockInterface {
currentTime: Date;
setTime(d: Date): void;
}
class Clock implements ClockInterface {
currentTime: Date = new Date();
setTime(d: Date) {
this.currentTime = d;
}
constructor(h: number, m: number) {}
}
// 接口只能定义类的公开部分(公开属性、公开方法)
// 而不能定义私有部分,因此你不能通过接口来约束类的私有实现
// 如果你用构造签名声明一个接口再让一个类去实现的话,就会报错
interface ClockConstructor {
new (hour: number, minute: number);
}
// 报错
class Clock implements ClockConstructor {
// Class 'Clock' incorrectly implements interface 'ClockConstructor'.
// Type 'Clock' provides no match for the signature 'new (hour: number, minute: number): any'.
currentTime: Date;
constructor(h: number, m: number) {}
}
// 原因 当类实现一个接口的时候,类实现的是实例的接口(而非构造函数的)
// 定义了两个接口,
// 构造函数类型 ClockConstructor 和实例类型 ClockInterface,
// 再定义了一个创建实例的函数 createClock,该函数返回第一个参数的实例
// 构造函数类型接口 ClockConstructor
interface ClockConstructor {
new (hour: number, minute: number): ClockInterface;
}
// 实例类型 ClockInterface
interface ClockInterface {
tick(): void;
}
/**
* @description: 创建实例函数
* @param {type} ctor:ClockConstructor
* @return: ClockInterface的实例
*/
function createClock(ctor: ClockConstructor, hour: number, minute: number): ClockInterface {
return new ctor(hour, minute);
}
class DigitalClock implements ClockInterface {
constructor(h: number, m: number) {}
tick() {
console.log('beep beep');
}
}
class AnalogClock implements ClockInterface {
constructor(h: number, m: number) {}
tick() {
console.log('tick tock');
}
}
let digital = createClock(DigitalClock, 12, 17);
let analog = createClock(AnalogClock, 7, 32);
// createClock 的第一个参数应该拥有 ClockConstructor 类型,
// 因此该函数会检查传递进来的 DigitalClock 和 AnalogClock 的构造函数是否是 ClockConstructor 类型
// 两个类型结合起来,就是通过类表达式(而非类声明)
interface ClockConstructor {
new (hour: number, minute: number);
}
interface ClockInterface {
tick();
}
const Clock: ClockConstructor = class Clock implements ClockInterface {
constructor(h: number, m: number) {}
tick() {
console.log('beep beep');
}
};
// const Clock: ClockConstructor 声明了类的构造函数类型,
// 而后面的 class Clock implements ClockInterface 则声明了类的实例类型。
interface interfaceA {
a:number;
}
interface interfaceB {
b:string;
}
interface interfaceC extends interfaceA,interfaceB {
c:boolean;
}
let interC:interfaceC = {};
// 定义的同名属性的类型不同的话,是不能编译通过的
interface Shape {
color: string;
test: number; // <-
}
interface PenStroke extends Shape{
penWidth: number;
test: string; // <-
}
interface Counter {
(start: number): string;
interval: number;
reset(): void;
}
function getCounter(): Counter {
let counter = function (start: number) {} as Counter;
counter.interval = 123;
counter.reset = function () {};
return counter;
}
let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;
// 当一个接口继承自类时,
// 这个接口就继承了类的所有成员和对应的类型,但是不会继承实现。
// 继承自类的接口甚至会继承类的 private 和 protected 属性,
// 因此一个继承自类的接口,只能由被继承的类或者其子类实现
class Control {
private state: any;
}
interface SelectableControl extends Control {
select(): void;
}
class Button extends Control implements SelectableControl {
select() {}
}
class TextBox extends Control {
select() {}
}
class ImageControl implements SelectableControl {
// Class 'ImageControl' incorrectly implements interface 'SelectableControl'.
// Types have separate declarations of a private property 'state'.
private state: any;
select() {}
}
// SelectableControl 继承了 Control 的所有成员,包括 private 属性 state,
// 因此能实现 SelectableControl 接口的类一定是继承自 Control 或其子类的类,
// 因为只有 Control 中的 state 才是 SelectableControl 中定义的 state 的原始实现(即使在继承类中实现了 state 也不行,因为 state 是 Control 私有的)。
// 实现了 SelectableControl 接口的实例可以通过 Control 访问私有属性 state。
// 事实上,SelectableControl 就像 Control 有 select() 方法一样。
// Button 和 TextBox 是 SelectableControl 的子类,因为他们继承自 Control 且拥有 select() 方法,
// 而 ImageControl 有自己的 private 属性 state 而不是从 Control 继承,因此它就无法实现 SelectableControl 接口了
Notion – The all-in-one workspace for your notes, tasks, wikis, and databases.https://serious-lose.notion.site/TS-Interface-439d14dd883148efbc23929fb1a7647d