:::commend{title="answer"}
接口用于定义对象应具有的属性、方法及其类型。也可以用来定义类、函数、数组等的结构
:::
// 1、 定义对象结构
interface Car {
brand: string;
speed: number;
drive(): void;
}
let myCar: Car = {
brand: "Toyota",
speed: 120,
drive() {
console.log("Driving at speed: " + this.speed);
}
};
// 2、指定接口只读和可选
interface Point {
readonly x: number; // 只读
readonly y: number; // 只读
z?: number; // 可选
}
let p1: Point = { x: 10, y: 20 };
:::commend{title="answer"}
:::assert{title="使用场景"}
:::commend{title="answer"}
let value: unknown;
value = 42;
// 需要先做类型检查,才能调用 `toFixed` 方法
if (typeof value === "number") {
value.toFixed(); // 正确
}
value = "Hello";
// 需要先做类型检查,才能调用 `toUpperCase` 方法
if (typeof value === "string") {
value.toUpperCase(); // 正确
}
:::assert{title="使用场景"}
:::commend{title="answer"}
// 抛出异常
function throwError(message: string): never {
throw new Error(message);
}
// 无限循环
function infiniteLoop(): never {
while (true) {
// 无限循环,永远不会返回
}
}
// 穷尽检查
type Shape = 'circle' | 'square';
function getArea(shape: Shape): number {
switch (shape) {
case 'circle':
return Math.PI * 1 ** 2;
case 'square':
return 1 * 1;
default:
const _exhaustiveCheck: never = shape; // 这里的 `shape` 永远不会是其他值
throw new Error(`Unexpected shape: ${shape}`);
}
}
:::commend{title="answer"}
function logMessage(message: string): void {
console.log(message); // 该函数返回 `undefined`
}
function throwError(message: string): never {
throw new Error(message); // 该函数永远不会返回
}
- 联合类型 允许一个变量可以是多种类型中的一种。使用 |(竖线)符号来定义。
- 场景: 用于表示某个值可以是多个不同类型中的一种,比如函数参数可以接受多种类型的数据。
let value: string | number;
function formatInput(input: string | number): string {
if (typeof input === "string") {
return input.toUpperCase();
} else {
return input.toFixed(2);
}
}
- 交叉类型 将多个类型合并为一个类型,该类型同时拥有所有类型的特性。使用 &(和符号)定义。
- 场景: 用于组合多个类型的属性,创建一个拥有所有属性的对象类型。
interface Person {
name: string;
}
interface Employee {
id: number;
}
let employee: Person & Employee = {
name: "Alice",
id: 123
};
function printEmployee(employee: Person & Employee) {
console.log(`Name: ${employee.name}, ID: ${employee.id}`);
}
- 类型别名 用来为一个类型创建一个新的名称(别名)。通过 type 关键字定义,适用于基本类型、联合类型、交叉类型等。
- 场景: 用于简化复杂类型,提升代码的可读性。它可以为对象、函数、联合类型等复杂类型创建简单的别名。
type ID = string | number;
let userId: ID = "abc123";
type User = {
name: string;
age: number;
};
function greet(user: User) {
console.log(`Hello, ${user.name}`);
}
类型保护 是 ts 中用于判断某个值的实际类型,并根据该类型进行进一步处理的技术。它在使用联合类型时非常有用,确保在不同类型的分支中能正确地执行相应的操作。
function printId(id: string | number) {
if (typeof id === "string") {
console.log(id.toUpperCase());
} else {
console.log(id.toFixed(2));
}
}
class Dog {
bark() {
console.log("Woof!");
}
}
class Cat {
meow() {
console.log("Meow!");
}
}
function makeSound(animal: Dog | Cat) {
if (animal instanceof Dog) {
animal.bark();
} else {
animal.meow();
}
}
function isString(value: any): value is string {
return typeof value === "string";
}
function printValue(value: string | number) {
if (isString(value)) {
console.log(value.toUpperCase());
} else {
console.log(value.toFixed(2));
}
}
interface Bird {
fly(): void;
}
interface Fish {
swim(): void;
}
function move(animal: Bird | Fish) {
if ("fly" in animal) {
animal.fly();
} else {
animal.swim();
}
}
:::commend{title="answer"}
// 1、复用已有变量的类型
let person = {
name: "Alice",
age: 25,
};
type PersonType = typeof person; // { name: string; age: number; }
// 2、函数返回类型
function getPerson() {
return { name: "Alice", age: 25 };
}
type PersonType = typeof getPerson(); // { name: string; age: number; }
// 3、JavaScript 中的类型检查
function printValue(value: number | string) {
if (typeof value === "string") {
console.log("This is a string: ", value);
} else {
console.log("This is a number: ", value);
}
}
:::commend{title="answer"}
// 1、获取对象类型的键
type Person = {
name: string;
age: number;
location: string;
};
type PersonKeys = keyof Person; // 'name' | 'age' | 'location'
// 2、类型约束(key必须是obj的对象键)
function getValue<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const person = { name: "Alice", age: 25, location: "NYC" };
const name = getValue(person, "name");
const age = getValue(person, "age");
:::commend{title="answer"}
枚举用于定义一组固定的、命名的常量,适合处理有限的选项集、状态、方向或权限。使用关键字 enum 定义
:::
enum ResultEnum {
SUCCESS = 200,
ERROR = 500,
NOTLOGGED = 401,
OVERDUE = 402,
TIMEOUT = 5000,
}
enum LogLevel {
Info,
Warn,
Error
}
enum Direction {
Up,
Down,
Left,
Right
}
type DirectionType = keyof typeof Direction; // Up | Down | Left | Right
:::commend{title="answer"}
// 简单泛型函数
function echo<T>(arg: T): T {
return arg;
}
echo<number>(42); // 传入 number 类型
// 泛型接口
interface Box<T> {
content: T;
}
// 默认泛型类型
function createArray<T = string>(length: number, value: T): T[] {
return Array(length).fill(value);
}
规定泛型参数必须符合某些条件,比如必须具有某些属性或方法。
interface Lengthwise {
length: number;
}
function logLength<T extends Lengthwise>(arg: T): T {
console.log(arg.length);
return arg;
}
logLength("Hello"); // 字符串有 length 属性,合法
// logLength(123); // 这里会报错,因为 number 类型没有 length 属性
:::commend{title="answer"}
let someValue: any = "This is a string";
// 我们知道 someValue 是 string 类型
let strLength: number = (someValue as string).length;
let colors = ["red", "green", "blue"] as const;
// `colors` 的类型将是 readonly ["red", "green", "blue"]
:::commend{title="answer"}
let tuple: [string, number];
tuple = ["Hello", 42]; // 合法
// tuple = [42, "Hello"]; // 非法,顺序错误
:::assert{title="使用场景"}
function getUserInfo(): [string, number] {
return ["Alice", 25];
}
let entry: [string, number] = ["score", 100];
console.log(entry[0]); // 输出 "score"
// 可选元素的元组
type FlexibleTuple = [string, number?, boolean?];
let tuple1: FlexibleTuple = ["Hello"];
:::commend{title="answer"}
// 重载签名(没有实现)
function format(input: number): string;
function format(input: Date): string;
// 实现签名(包含逻辑)
function format(input: any): string {
if (typeof input === "number") {
return input.toFixed(2); // 格式化数字
} else if (input instanceof Date) {
return input.toISOString(); // 格式化日期
}
}
// 不同数量、类型参数
function greet(name: string): string;
function greet(firstName: string, lastName: string): string;
function greet(firstName: string, lastName?: string): string {
if (lastName) {
return `Hello, ${firstName} ${lastName}!`;
} else {
return `Hello, ${firstName}!`;
}
}
条件类型通常以 T extends U ? X : Y 这样的形式书写,其中 T extends U 表示条件判断,如果条件为真则返回类型 X,否则返回类型 Y。这类似于 JavaScript 中的三元操作符 condition ? trueValue : falseValue。
T extends U ? X : Y
// • T extends U:表示条件,检查类型 T 是否可以赋值给类型 U。
// • X:当 T 满足条件(即 T extends U 为 true)时返回的类型。
// • Y:当 T 不满足条件(即 T extends U 为 false)时返回的类型。
// 示例:
type IsString<T> = T extends string ? "Yes" : "No";
type A = IsString<string>; // "Yes"
type B = IsString<number>; // "No"
将类型 T 的所有属性变为可选属性。
name: string;
age: number;
}
type PartialPerson = Partial<Person>;
// PartialPerson 等价于 { name?: string; age?: number; }
将类型 T 的所有属性变为必选属性。
interface Person {
name?: string;
age?: number;
}
type RequiredPerson = Required<Person>;
// RequiredPerson 等价于 { name: string; age: number; }
将类型 T 的所有属性变为只读属性,不允许修改。
interface Person {
name: string;
age: number;
}
type ReadonlyPerson = Readonly<Person>;
// ReadonlyPerson 等价于 { readonly name: string; readonly age: number; }
从类型 T 中选取部分属性组成新类型。K 是需要选取的属性的联合类型。
interface Person {
name: string;
age: number;
address: string;
}
type PersonNameAndAge = Pick<Person, "name" | "age">;
// PersonNameAndAge 等价于 { name: string; age: number; }
从类型 T 中排除 K 指定的属性,构造新类型。
interface Person {
name: string;
age: number;
address: string;
}
type PersonWithoutAddress = Omit<Person, "address">;
// PersonWithoutAddress 等价于 { name: string; age: number; }
构造一个类型,键 K 可以是字符串、数字等,值 T 是所有属性的类型。
type Page = "home" | "about" | "contact";
type PageInfo = { title: string };
const pages: Record<Page, PageInfo> = {
home: { title: "Home Page" },
about: { title: "About Us" },
contact: { title: "Contact Us" },
};
从联合类型 T 中排除所有属于类型 U 的子类型。
type A = "a" | "b" | "c";
type B = "a";
type Result = Exclude<A, B>; // "b" | "c"
从联合类型 T 中提取所有可以赋值给类型 U 的子类型。
type A = "a" | "b" | "c";
type B = "a" | "b";
type Result = Extract<A, B>; // "a" | "b"
排除类型 T 中的 null 和 undefined。
type A = string | null | undefined;
type NonNullableA = NonNullable<A>; // string
获取函数类型 T 的返回值类型。
function getUser() {
return { name: "Alice", age: 25 };
}
type UserType = ReturnType<typeof getUser>;
// UserType 等价于 { name: string; age: number; }
获取构造函数类型 T 的实例类型。
class Person {
name: string = "Alice";
age: number = 25;
}
type PersonInstance = InstanceType<typeof Person>;
// PersonInstance 等价于 Person
获取函数类型 T 的参数类型,返回一个元组类型。
function greet(name: string, age: number): string {
return `Hello ${name}, you are ${age} years old.`;
}
type GreetParams = Parameters<typeof greet>;
// GreetParams 等价于 [string, number]
获取构造函数类型 T 的参数类型,返回一个元组类型。
class Person {
constructor(public name: string, public age: number) {}
}
type PersonConstructorParams = ConstructorParameters<typeof Person>;
// PersonConstructorParams 等价于 [string, number]
用于指定上下文对象 this 的类型,通常与 noImplicitThis 选项配合使用。
type ObjectDescriptor<D, M> = {
data?: D;
methods?: M & ThisType<D & M>; // M中的this会被推断为 D & M 类型
};
let obj: ObjectDescriptor<{ x: number }, { foo(): void }> = {
data: { x: 10 },
methods: {
foo() {
console.log(this.x); // 推断为 number
}
}
};
获取一个 Promise 的解析类型。
type P = Promise<string>;
type Result = Awaited<P>; // string
:::commend{title="answer"}
:::commend{title="answer"}
<template>
<MyComponent ref="myComponentRef" message="Hello, World!" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import MyComponent from './MyComponent.vue';
const myComponentRef = ref<InstanceType<typeof MyComponent> | null>(null)
</script>
https://typescript.p6p.net/typescript-tutorial/tsconfig.json.html#compileoptions
{
// 编译选项
"compilerOptions": {
// 指定 ECMAScript 目标版本(如 ES5, ES6, ESNext)。
"target": "ES6",
// 指定使用的模块系统
"module": "ESNext",
// 启用所有严格类型检查选项的标志。
"strict": true,
// 启用对 ES 模块的互操作性支持。
"esModuleInterop": true,
// 生成 .map 文件,用于调试。
"sourceMap": true,
// 指定 JSX 代码的编译方式(如 react, react-jsx, preserve)。
"jsx": "preserve",
// 指定使用的库文件(如 DOM, ES6, ESNext)。
"lib": ["ES6", "DOM"],
// 指定使用的库文件(如 DOM, ES6, ESNext)。
"skipLibCheck": true,
// 在没有类型注解的情况下禁止隐式 any 类型。
"noImplicitAny": true,
// 生成声明文件,开启后会自动生成声明文件
"declaration": true,
// 指定生成声明文件存放目录
"declarationDir": "./file",
// 只生成声明文件,而不会生成js文件
"emitDeclarationOnly": true,
// 允许export=导出,由import from 导入
"esModuleInterop": true,
// 解析非相对模块的基地址,默认是当前目录
"baseUrl": "./",
// 路径映射,相对于baseUrl
"paths": {
"@/*": ["./src/*"]
},
// ...
},
// 包含的文件或目录
"include": [],
// 排除的文件或目录
"exclude": [],
// 指定编译的具体文件列表,适用于小型项目。
"files": [],
// 用于支持项目间的引用,适用于大型项目。
"references": []
// 继承其他配置
"extends": ""
}