TypeScript
-
使用无效合并运算符引发内联误差
很多时候,如果特定值为 null 或未定义,我们发现自己需要抛出错误。TypeScript 提供了一种使用空合并运算符 (??) 和简单的帮助程序函数来内联此过程的方法,而不是手动检查。
const raise = (err: string) : never => { throw new Error(err);};
这个“raise”函数与 nullish 合并运算符结合使用时,允许您编写更具可读性和简洁的代码。
const Page = (props: { params: { id?: string }}) => { const id = props.params.id ?? raise('No id provided'); };
注:never
在 TypeScript 中,
never
是一个表示永远不会发生的类型。它表示一个函数永远不会返回任何值,或者一个函数抛出一个异常。
raise
是一个函数,它接受一个字符串参数 err
,并且返回类型被声明为 never
。这意味着当调用 raise
函数时,它会抛出一个错误并终止程序的执行,而不会返回任何值。
使用 never
类型可以用于以下几种情况:
- 抛出异常:当函数遇到错误或不可恢复的情况时,可以使用
never
类型来表示函数会抛出一个异常并终止程序的执行。
function throwError(message: string): never {
throw new Error(message);
}
throwError("Something went wrong!"); // 抛出错误并终止程序的执行
- 无限循环:当函数进入一个无限循环时,可以使用
never
类型来表示函数永远不会返回。
function infiniteLoop(): never {
while (true) {
// 无限循环
}
}
infiniteLoop(); // 永远不会返回
- 类型推断:当 TypeScript 无法推断出函数的返回类型时,可以使用
never
类型来明确指定函数永远不会返回。
function unreachableCode(): never {
return 42; // 错误:返回类型不匹配
}
总结:never
类型表示一个函数永远不会返回任何值或抛出异常。它在处理错误、无限循环或指定函数的返回类型时非常有用。
-
利用映射类型
映射类型是一个强大的 TypeScript 功能,允许您基于现有类型创建新类型。它们可以帮助您保持类型干燥,减少重复并提高可维护性。
-
Readonly
interface IUser { name: string; age: number; } type ReadonlyUser = Readonly<IUser>;
现在,ReadonlyUser类型的队形 的所有属性都是只读的。
-
Partial
type PartialUser = Partial<IUser>;
PartialUser
现在是{ name?: string, age?: number }
-
Record
映射类型可用于创建属性键所在的对象类型,属性值为 :
Record<K,T>
K
T
type UserRecord = Record<string, IUser>;
UserRecord
现在是一个对象类型,它将接受任何字符串作为键,并且任何值都必须是 类型。IUser
创建自己的映射类型
您不仅限于 TypeScript 提供的映射类型。您还可以创建自己的:
type Nullable<T> = { [P in keyof T]: T[P] | null };
此类型采用现有类型,并生成一个新类型,其中每个属性都可为空。
Nullable<T>``T
映射类型可帮助您基于现有类型创建复杂类型,从而减少代码重复并增强类型安全性。
注: Ts中 keyof 关键字的使用
keyof 是 TypeScript 中的一个关键字,用于获取一个类型的所有键的联合类型。它可以用于获取一个对象类型的所有键,也可以用于获取一个联合类型的所有共有键。
例如,假设有一个对象类型:
type Person = { name: string; age: number; gender: string; };
可以使用 keyof 来获取该类型的所有键:
type PersonKeys = keyof Person; // PersonKeys 的类型为 "name" | "age" | "gender"
同样,keyof 也可以用于获取一个联合类型的所有共有键。例如:
type Animal = { name: string; age: number; }; type Plant = { name: string; color: string; }; type Organism = Animal | Plant; type OrganismKeys = keyof Organism; // OrganismKeys 的类型为 "name"
在这个例子中,联合类型 Organism 中只有 name 这个键是共有的,所以 OrganismKeys 的类型只包含 “name”。
注:Ts 中 in关键字的作用
在 TypeScript 中,in 是一个关键字,用于判断一个属性是否存在于一个对象或者类型中。
它可以用在两个不同的场景中:
- 在类型保护中使用:可以使用 in 操作符来检查一个属性是否存在于一个对象中,从而进行类型保护。例如:
interface Person { name: string; age?: number; } function printPersonInfo(person: Person) { if ('age' in person) { console.log(`${person.name} is ${person.age} years old.`); } else { console.log(`${person.name} has no age specified.`); } } const person1: Person = { name: 'John', age: 25, }; const person2: Person = { name: 'Alice', }; printPersonInfo(person1); // Output: John is 25 years old. printPersonInfo(person2); // Output: Alice has no age specified.
在上面的例子中,我们使用 in 操作符来检查 person 对象是否具有 age 属性。如果有,就打印年龄信息;如果没有,就打印没有指定年龄的信息。
- 在 for…in 循环中使用:可以使用 in 操作符来迭代一个对象的所有属性。例如:
interface Person { name: string; age: number; gender: string; } const person: Person = { name: 'John', age: 25, gender: 'male', }; for (const key in person) { console.log(`${key}: ${person[key]}`); } // Output: // name: John // age: 25 // gender: male
在上面的例子中,我们使用 for…in 循环来迭代 person 对象的所有属性,并打印每个属性的键和对应的值。
总结:in 关键字在 TypeScript 中用于判断属性是否存在于一个对象或类型中,并在类型保护和循环迭代中发挥作用.
-
-
类型防护
TypeScript 支持用户定义的类型保护,以缩小条件块中对象的类型。这是通过使用返回布尔值的函数来实现的,该函数指示对象是否属于特定类型。
function isString(test: any): test is string { return typeof test === "string"; } function printLength(input: string | any[]) { if (isString(input)) { console.log(input.length); } else { console.log(input.length); } }
在此示例中,是一个类型保护,可确保在 if 块中被视为字符串。
isString``input
注:类型谓词的用法
类型谓词的语法是
parameterName is Type
,其中parameterName
是函数参数的名称,Type
是要判断的类型。当函数返回值为布尔类型时,test is string
表示如果test
是一个字符串类型,则返回true
,否则返回false
。以下是一些更多的例子,展示了如何使用类型谓词来进行类型保护:
function isNumber(test: any): test is number { return typeof test === "number"; } function isObject(test: any): test is object { return typeof test === "object" && test !== null; } function isBoolean(test: any): test is boolean { return typeof test === "boolean"; } function isUndefined(test: any): test is undefined { return typeof test === "undefined"; } interface Person { name: string; age: number; } function isPerson(test: any): test is Person { return typeof test === "object" && test !== null && "name" in test && "age" in test; }
在上面的例子中,我们定义了一些类型谓词函数,用于判断不同的类型。例如,
isNumber
函数判断一个值是否为数字类型,isObject
函数判断一个值是否为对象类型,isPerson
函数判断一个值是否为Person
类型。这些类型谓词函数可以在类型保护中使用,以便在代码中进行类型推断和类型检查。例如:
function printValue(value: any) { if (isString(value)) { console.log(value.toUpperCase()); } else if (isNumber(value)) { console.log(value.toFixed(2)); } else if (isObject(value)) { console.log(Object.keys(value)); } } printValue("hello"); // Output: HELLO printValue(3.14159); // Output: 3.14 printValue({ name: "John", age: 25 }); // Output: [ 'name', 'age' ]
在上面的例子中,
printValue
函数接受一个参数value
,并根据不同的类型进行不同的处理。使用类型谓词函数可以在调用printValue
函数时进行类型保护,以确保在处理value
时能够正确推断其类型。 -
强制实施只读属性
TypeScript 具有修饰符,可以轻松创建设置后无法更改的属性。这对于创建具有不应更改的属性的对象特别有用。
readonly
interface Config { readonly apiUrl: string; readonly defaultTimeout: number; } const config: Config = { apiUrl: "https://myapi.com", defaultTimeout: 5000, }; config.apiUrl = "https://anotherapi.com"; // Error!
在此示例中,任何更改 或 的尝试都将导致 TypeScript 错误。
apiUrl``defaultTimeout