泛型和类型体操
泛型和类型体操(Type Gymnastics)是 TypeScript 中高级类型系统的重要组成部分。它们提供了强大的工具和技巧,用于处理复杂的类型操作和转换。
泛型(Generics)
1. 泛型函数
泛型函数允许我们在函数定义中使用类型参数,以便在函数调用时动态指定类型。例如:
let result = identity<number>(42); // result 的类型为 number" aria-label="复制" data-bs-original-title="复制">
<i class="far fa-copy"></i>
</button>
</div>
</div><pre class="typescript hljs language-typescript"><span class="hljs-keyword">function</span> identity<T>(<span class="hljs-attr">arg</span>: T): T {
<span class="hljs-keyword">return</span> arg;
}
<span class="hljs-keyword">let</span> result = identity<<span class="hljs-built_in">number</span>>(<span class="hljs-number">42</span>); <span class="hljs-comment">// result 的类型为 number</span></pre><p>在上面的示例中,<code>identity</code> 函数使用类型参数 <code>T</code>,并返回与输入类型相同的值。通过显式传递泛型参数,我们可以确保在函数调用时指定了具体的类型。</p><h4>2. 泛型接口</h4><p>泛型接口允许我们在接口定义中使用类型参数,以便在实现该接口时指定具体的类型。例如:</p><div class="widget-codetool" style="display: none;">
<div class="widget-codetool--inner">
<button type="button" class="btn btn-dark rounded-0 sflex-center copyCode" data-toggle="tooltip" data-placement="top" data-clipboard-text="interface Container<T> {
value: T;
}
let container: Container<number> = { value: 42 };" aria-label="复制" data-bs-original-title="复制">
<i class="far fa-copy"></i>
</button>
</div>
</div><pre class="typescript hljs language-typescript"><span class="hljs-keyword">interface</span> <span class="hljs-title class_">Container</span><T> {
<span class="hljs-attr">value</span>: T;
}
<span class="hljs-keyword">let</span> <span class="hljs-attr">container</span>: <span class="hljs-title class_">Container</span><<span class="hljs-built_in">number</span>> = { <span class="hljs-attr">value</span>: <span class="hljs-number">42</span> };</pre><p>在上面的示例中,我们定义了一个泛型接口 <code>Container</code>,它包含一个类型参数 <code>T</code>。通过指定 <code>Container<number></code>,我们创建了一个具体的实现,其中的 <code>value</code> 属性类型为 <code>number</code>。</p><h4>3. 泛型类</h4><p>泛型类允许我们在类定义中使用类型参数,以便在创建类的实例时指定具体的类型。例如:</p><div class="widget-codetool" style="display: none;">
<div class="widget-codetool--inner">
<button type="button" class="btn btn-dark rounded-0 sflex-center copyCode" data-toggle="tooltip" data-placement="top" data-clipboard-text="class Stack<T> {
private items: T[] = [];
push(item: T) {
this.items.push(item);
}
pop(): T | undefined {
return this.items.pop();
}
}
let stack = new Stack<number>();
stack.push(1);
stack.push(2);
let item = stack.pop(); // item 的类型为 number | undefined" aria-label="复制" data-bs-original-title="复制">
<i class="far fa-copy"></i>
</button>
</div>
</div><pre class="typescript hljs language-typescript"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Stack</span><T> {
<span class="hljs-keyword">private</span> <span class="hljs-attr">items</span>: T[] = [];
<span class="hljs-title function_">push</span>(<span class="hljs-params">item: T</span>) {
<span class="hljs-variable language_">this</span>.<span class="hljs-property">items</span>.<span class="hljs-title function_">push</span>(item);
}
<span class="hljs-title function_">pop</span>(): T | <span class="hljs-literal">undefined</span> {
<span class="hljs-keyword">return</span> <span class="hljs-variable language_">this</span>.<span class="hljs-property">items</span>.<span class="hljs-title function_">pop</span>();
}
}
<span class="hljs-keyword">let</span> stack = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Stack</span><<span class="hljs-built_in">number</span>>();
stack.<span class="hljs-title function_">push</span>(<span class="hljs-number">1</span>);
stack.<span class="hljs-title function_">push</span>(<span class="hljs-number">2</span>);
<span class="hljs-keyword">let</span> item = stack.<span class="hljs-title function_">pop</span>(); <span class="hljs-comment">// item 的类型为 number | undefined</span></pre><p>在上面的示例中,我们定义了一个泛型类 <code>Stack</code>,它使用类型参数 <code>T</code> 来表示堆栈中的元素类型。通过创建 <code>Stack<number></code> 的实例,我们限制了堆栈中的元素必须为 <code>number</code> 类型。</p><h3 id="item-1-2">类型体操(Type Gymnastics)</h3><h4>1. 条件类型(Conditional Types)</h4><p>条件类型允许我们根据输入类型的条件判断结果来选择不同的类型。条件类型的语法形式为:</p><div class="widget-codetool" style="display: none;">
<div class="widget-codetool--inner">
<button type="button" class="btn btn-dark rounded-0 sflex-center copyCode" data-toggle="tooltip" data-placement="top" data-clipboard-text="T extends U ? X : Y" aria-label="复制" data-bs-original-title="复制">
<i class="far fa-copy"></i>
</button>
</div>
</div><pre class="typescript hljs language-typescript">T <span class="hljs-keyword">extends</span> U ? X : Y</pre><p>其中,<code>T</code> 是待检查的类型,<code>U</code> 是条件类型,<code>X</code> 是满足条件时返回的类型,<code>Y</code> 是不满足条件时返回的类型。</p><p>下面是一个使用条件类型的示例:</p><div class="widget-codetool" style="display: none;">
<div class="widget-codetool--inner">
<button type="button" class="btn btn-dark rounded-0 sflex-center copyCode" data-toggle="tooltip" data-placement="top" data-clipboard-text="type Check<T> = T extends string ? true : false;
type Result = Check<string>; // Result 的类型为 true" aria-label="复制" data-bs-original-title="复制">
<i class="far fa-copy"></i>
</button>
</div>
</div><pre class="typescript hljs language-typescript"><span class="hljs-keyword">type</span> <span class="hljs-title class_">Check</span><T> = T <span class="hljs-keyword">extends</span> <span class="hljs-built_in">string</span> ? <span class="hljs-literal">true</span> : <span class="hljs-literal">false</span>;
<span class="hljs-keyword">type</span> <span class="hljs-title class_">Result</span> = <span class="hljs-title class_">Check</span><<span class="hljs-built_in">string</span>>; <span class="hljs-comment">// Result 的类型为 true</span></pre><p>在上面的示例中,我们定义了一个条件</p><p>类型 <code>Check<T></code>,它接受一个类型参数 <code>T</code>。如果 <code>T</code> 是 <code>string</code> 类型,那么 <code>Check<T></code> 的类型将是 <code>true</code>,否则为 <code>false</code>。</p><h4>2. <code>keyof</code> 操作符和索引访问类型</h4><p><code>keyof</code> 操作符用于获取类型的所有属性名,结合索引访问类型可以从一个类型中获取属性的具体类型。</p><div class="widget-codetool" style="display: none;">
<div class="widget-codetool--inner">
<button type="button" class="btn btn-dark rounded-0 sflex-center copyCode" data-toggle="tooltip" data-placement="top" data-clipboard-text="interface Person {
name: string;
age: number;
}
type PersonKeys = keyof Person; // "name" | "age"
type PersonNameType = Person['name']; // string" aria-label="复制" data-bs-original-title="复制">
<i class="far fa-copy"></i>
</button>
</div>
</div><pre class="typescript hljs language-typescript"><span class="hljs-keyword">interface</span> <span class="hljs-title class_">Person</span> {
<span class="hljs-attr">name</span>: <span class="hljs-built_in">string</span>;
<span class="hljs-attr">age</span>: <span class="hljs-built_in">number</span>;
}
<span class="hljs-keyword">type</span> <span class="hljs-title class_">PersonKeys</span> = keyof <span class="hljs-title class_">Person</span>; <span class="hljs-comment">// "name" | "age"</span>
<span class="hljs-keyword">type</span> <span class="hljs-title class_">PersonNameType</span> = <span class="hljs-title class_">Person</span>[<span class="hljs-string">'name'</span>]; <span class="hljs-comment">// string</span></pre><p>在上面的示例中,我们使用 <code>keyof</code> 操作符获取了 <code>Person</code> 接口的属性名集合,并通过索引访问类型获取了 <code>Person</code> 接口中 <code>name</code> 属性的类型。</p><h4>3. <code>infer</code> 关键字</h4><p><code>infer</code> 关键字用于在条件类型中推断类型,并将其赋值给一个类型变量。</p><div class="widget-codetool" style="display: none;">
<div class="widget-codetool--inner">
<button type="button" class="btn btn-dark rounded-0 sflex-center copyCode" data-toggle="tooltip" data-placement="top" data-clipboard-text="type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
function add(a: number, b: number): number {
return a + b;
}
type AddReturnValue = ReturnType<typeof add>; // 类型为 number" aria-label="复制" data-bs-original-title="复制">
<i class="far fa-copy"></i>
</button>
</div>
</div><pre class="typescript hljs language-typescript"><span class="hljs-keyword">type</span> <span class="hljs-title class_">ReturnType</span><T> = T <span class="hljs-keyword">extends</span> (...<span class="hljs-attr">args</span>: <span class="hljs-built_in">any</span>[]) => infer R ? R : <span class="hljs-built_in">never</span>;
<span class="hljs-keyword">function</span> <span class="hljs-title function_">add</span>(<span class="hljs-params">a: <span class="hljs-built_in">number</span>, b: <span class="hljs-built_in">number</span></span>): <span class="hljs-built_in">number</span> {
<span class="hljs-keyword">return</span> a + b;
}
<span class="hljs-keyword">type</span> <span class="hljs-title class_">AddReturnValue</span> = <span class="hljs-title class_">ReturnType</span><<span class="hljs-keyword">typeof</span> add>; <span class="hljs-comment">// 类型为 number</span></pre><p>在上面的示例中,<code>ReturnType</code> 类型接受一个类型参数 <code>T</code>,并使用条件类型和 <code>infer</code> 关键字推断函数类型的返回类型。通过调用 <code>ReturnType<typeof add></code>,我们推断出 <code>add</code> 函数的返回类型为 <code>number</code>。</p><p>当涉及到泛型时,还有一些重要的概念和内置泛型函数可以深入分析。让我们继续探讨 <code>extends</code> 关键字、TS 官方内置的一些泛型函数以及它们的使用。</p><h3 id="item-1-3"><code>extends</code> 关键字和类型约束</h3><p>在泛型中,我们可以使用 <code>extends</code> 关键字来对泛型类型进行约束。这样可以确保传递给泛型的类型满足特定条件。</p><div class="widget-codetool" style="display: none;">
<div class="widget-codetool--inner">
<button type="button" class="btn btn-dark rounded-0 sflex-center copyCode" data-toggle="tooltip" data-placement="top" data-clipboard-text="function printProperty<T extends { name: string }>(obj: T): void {
console.log(obj.name);
}
printProperty({ name: 'John', age: 25 }); // 输出 'John'" aria-label="复制" data-bs-original-title="复制">
<i class="far fa-copy"></i>
</button>
</div>
</div><pre class="typescript hljs language-typescript"><span class="hljs-keyword">function</span> printProperty<T <span class="hljs-keyword">extends</span> { <span class="hljs-attr">name</span>: <span class="hljs-built_in">string</span> }>(<span class="hljs-attr">obj</span>: T): <span class="hljs-built_in">void</span> {
<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(obj.<span class="hljs-property">name</span>);
}
<span class="hljs-title function_">printProperty</span>({ <span class="hljs-attr">name</span>: <span class="hljs-string">'John'</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">25</span> }); <span class="hljs-comment">// 输出 'John'</span></pre><p>在上面的示例中,<code>printProperty</code> 函数接受一个泛型参数 <code>T</code>,该参数必须满足一个约束条件:具有 <code>name</code> 属性,且 <code>name</code> 的类型为 <code>string</code>。通过使用 <code>extends</code> 关键字和类型约束,我们可以确保 <code>obj</code> 参数具有所需的属性和类型,从而避免出现错误。</p><h4>泛型函数Util</h4><p>TypeScript 提供了一些内置的泛型函数,这些函数被广泛用于处理各种类型操作。以下是一些常见的官方内置泛型函数:</p><h5><code>Partial<T></code></h5><p><code>Partial<T></code> 是 TypeScript 中的一个内置泛型类型,它可以将给定类型 <code>T</code> 中的所有属性转换为可选属性。这对于创建部分完整的对象非常有用。</p><div class="widget-codetool" style="display: none;">
<div class="widget-codetool--inner">
<button type="button" class="btn btn-dark rounded-0 sflex-center copyCode" data-toggle="tooltip" data-placement="top" data-clipboard-text="interface Person {
name: string;
age: number;
}
type PartialPerson = Partial<Person>;
const partialPerson: PartialPerson = { name: 'John' }; // age 属性是可选的" aria-label="复制" data-bs-original-title="复制">
<i class="far fa-copy"></i>
</button>
</div>
</div><pre class="typescript hljs language-typescript"><span class="hljs-keyword">interface</span> <span class="hljs-title class_">Person</span> {
<span class="hljs-attr">name</span>: <span class="hljs-built_in">string</span>;
<span class="hljs-attr">age</span>: <span class="hljs-built_in">number</span>;
}
<span class="hljs-keyword">type</span> <span class="hljs-title class_">PartialPerson</span> = <span class="hljs-title class_">Partial</span><<span class="hljs-title class_">Person</span>>;
<span class="hljs-keyword">const</span> <span class="hljs-attr">partialPerson</span>: <span class="hljs-title class_">PartialPerson</span> = { <span class="hljs-attr">name</span>: <span class="hljs-string">'John'</span> }; <span class="hljs-comment">// age 属性是可选的</span></pre><p>在上面的示例中,<code>Partial<Person></code> 将 <code>Person</code> 接口中的所有属性变为可选属性,从而创建了一个部分完整的 <code>PartialPerson</code> 类型。</p><h5><code>Required<T></code></h5><p><code>Required<T></code> 是 TypeScript 中的另一个内置泛型类型,它可以将给定类型 <code>T</code> 中的所有可选属性转换为必需属性。这对于确保对象的完整性非常有用。</p><div class="widget-codetool" style="display: none;">
<div class="widget-codetool--inner">
<button type="button" class="btn btn-dark rounded-0 sflex-center copyCode" data-toggle="tooltip" data-placement="top" data-clipboard-text="interface Person {
name?: string;
age?: number;
}
type RequiredPerson = Required<Person>;
const requiredPerson: RequiredPerson = { name: 'John', age: 25 }; // name 和 age 属性是必需的" aria-label="复制" data-bs-original-title="复制">
<i class="far fa-copy"></i>
</button>
</div>
</div><pre class="typescript hljs language-typescript"><span class="hljs-keyword">interface</span> <span class="hljs-title class_">Person</span> {
name?: <span class="hljs-built_in">string</span>;
age?: <span class="hljs-built_in">number</span>;
}
<span class="hljs-keyword">type</span> <span class="hljs-title class_">RequiredPerson</span> = <span class="hljs-title class_">Required</span><<span class="hljs-title class_">Person</span>>;
<span class="hljs-keyword">const</span> <span class="hljs-attr">requiredPerson</span>: <span class="hljs-title class_">RequiredPerson</span> = { <span class="hljs-attr">name</span>: <span class="hljs-string">'John'</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">25</span> }; <span class="hljs-comment">// name 和 age 属性是必需的</span></pre><p>在上面的示例中,<code>Required<Person></code> 将 <code>Person</code> 接口中的所有可选属性变为必需属性,从而创建了一个要求完整性的 <code>RequiredPerson</code> 类型。</p><h5><code>Pick<T, K></code></h5><p><code>Pick<T, K></code> 是 TypeScript 中的另一个内置泛型函数,它可以从给定类型 <code>T</code> 中选择指定的属性 <code>K</code> 组成一个新的类型。</p><div class="widget-codetool" style="display: none;">
<div class="widget-codetool--inner">
<button type="button" class="btn btn-dark rounded-0 sflex-center copyCode" data-toggle="tooltip" data-placement="top" data-clipboard-text="interface Person {
name: string;
age: number;
address: string;
}
type NameAndAge = Pick<Person, 'name' | 'age'>;
const person: NameAndAge = { name:
'John', age: 25 }; // 只包含 name 和 age 属性" aria-label="复制" data-bs-original-title="复制">
<i class="far fa-copy"></i>
</button>
</div>
</div><pre class="typescript hljs language-typescript"><span class="hljs-keyword">interface</span> <span class="hljs-title class_">Person</span> {
<span class="hljs-attr">name</span>: <span class="hljs-built_in">string</span>;
<span class="hljs-attr">age</span>: <span class="hljs-built_in">number</span>;
<span class="hljs-attr">address</span>: <span class="hljs-built_in">string</span>;
}
<span class="hljs-keyword">type</span> <span class="hljs-title class_">NameAndAge</span> = <span class="hljs-title class_">Pick</span><<span class="hljs-title class_">Person</span>, <span class="hljs-string">'name'</span> | <span class="hljs-string">'age'</span>>;
<span class="hljs-keyword">const</span> <span class="hljs-attr">person</span>: <span class="hljs-title class_">NameAndAge</span> = { <span class="hljs-attr">name</span>:
<span class="hljs-string">'John'</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">25</span> }; <span class="hljs-comment">// 只包含 name 和 age 属性</span></pre><p>在上面的示例中,<code>Pick<Person, 'name' | 'age'></code> 从 <code>Person</code> 接口中选择了 <code>'name'</code> 和 <code>'age'</code> 属性,创建了一个新的类型 <code>NameAndAge</code>。</p><p>我们还可以结合泛型和内置泛型函数来实现更复杂的类型操作。以下是一个示例,展示了如何使用 <code>Pick</code> 和泛型来创建一个函数,该函数从给定对象中选择指定属性,并返回一个新的对象。</p><div class="widget-codetool" style="display: none;">
<div class="widget-codetool--inner">
<button type="button" class="btn btn-dark rounded-0 sflex-center copyCode" data-toggle="tooltip" data-placement="top" data-clipboard-text="function pickProperties<T, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> {
const result: Partial<T> = {};
for (const key of keys) {
result[key] = obj[key];
}
return result as Pick<T, K>;
}
interface Person {
name: string;
age: number;
address: string;
}
const person: Person = {
name: 'John',
age: 25,
address: '123 Main St'
};
const nameAndAge = pickProperties(person, ['name', 'age']); // 只包含 name 和 age 属性
console.log(nameAndAge); // 输出: { name: 'John', age: 25 }" aria-label="复制" data-bs-original-title="复制">
<i class="far fa-copy"></i>
</button>
</div>
</div><pre class="typescript hljs language-typescript"><span class="hljs-keyword">function</span> pickProperties<T, K <span class="hljs-keyword">extends</span> keyof T>(<span class="hljs-attr">obj</span>: T, <span class="hljs-attr">keys</span>: K[]): <span class="hljs-title class_">Pick</span><T, K> {
<span class="hljs-keyword">const</span> <span class="hljs-attr">result</span>: <span class="hljs-title class_">Partial</span><T> = {};
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> key <span class="hljs-keyword">of</span> keys) {
result[key] = obj[key];
}
<span class="hljs-keyword">return</span> result <span class="hljs-keyword">as</span> <span class="hljs-title class_">Pick</span><T, K>;
}
<span class="hljs-keyword">interface</span> <span class="hljs-title class_">Person</span> {
<span class="hljs-attr">name</span>: <span class="hljs-built_in">string</span>;
<span class="hljs-attr">age</span>: <span class="hljs-built_in">number</span>;
<span class="hljs-attr">address</span>: <span class="hljs-built_in">string</span>;
}
<span class="hljs-keyword">const</span> <span class="hljs-attr">person</span>: <span class="hljs-title class_">Person</span> = {
<span class="hljs-attr">name</span>: <span class="hljs-string">'John'</span>,
<span class="hljs-attr">age</span>: <span class="hljs-number">25</span>,
<span class="hljs-attr">address</span>: <span class="hljs-string">'123 Main St'</span>
};
<span class="hljs-keyword">const</span> nameAndAge = <span class="hljs-title function_">pickProperties</span>(person, [<span class="hljs-string">'name'</span>, <span class="hljs-string">'age'</span>]); <span class="hljs-comment">// 只包含 name 和 age 属性</span>
<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(nameAndAge); <span class="hljs-comment">// 输出: { name: 'John', age: 25 }</span></pre><p>在上面的示例中,<code>pickProperties</code> 函数接受一个泛型参数 <code>T</code> 和一个属性数组 <code>keys</code>。通过使用 <code>Pick<T, K></code>,我们将从给定对象 <code>obj</code> 中选择指定的属性 <code>keys</code>,并创建一个新的对象。</p><p>这个例子结合了泛型、内置泛型函数 <code>Pick</code>、<code>keyof</code> 操作符和 <code>extends</code> 关键字,展示了如何在 TypeScript 中处理复杂的类型操作和转换。</p><p>当涉及到官方内置的泛型函数时,还有一些重要的函数值得分析。让我们继续探讨一些常用的官方内置泛型函数以及它们的使用。</p><h4><code>Exclude<T, U></code></h4><p><code>Exclude<T, U></code> 是 TypeScript 中的一个内置泛型函数,用于从类型 <code>T</code> 中排除类型 <code>U</code>。它返回一个新类型,该新类型包含在 <code>T</code> 中存在但不在 <code>U</code> 中存在的成员类型。</p><div class="widget-codetool" style="display: none;">
<div class="widget-codetool--inner">
<button type="button" class="btn btn-dark rounded-0 sflex-center copyCode" data-toggle="tooltip" data-placement="top" data-clipboard-text="type T = Exclude<"a" | "b" | "c", "a" | "b">; // T 的类型为 "c"" aria-label="复制" data-bs-original-title="复制">
<i class="far fa-copy"></i>
</button>
</div>
</div><pre class="typescript hljs language-typescript"><span class="hljs-keyword">type</span> T = <span class="hljs-title class_">Exclude</span><<span class="hljs-string">"a"</span> | <span class="hljs-string">"b"</span> | <span class="hljs-string">"c"</span>, <span class="hljs-string">"a"</span> | <span class="hljs-string">"b"</span>>; <span class="hljs-comment">// T 的类型为 "c"</span></pre><p>在上面的示例中,<code>Exclude<"a" | "b" | "c", "a" | "b"></code> 排除了类型 <code>"a"</code> 和 <code>"b"</code>,返回类型为 <code>"c"</code>。</p><h4><code>Omit<T, K></code></h4><p><code>Omit<T, K></code> 是 TypeScript 中的另一个内置泛型函数,它返回一个新类型,该新类型排除了类型 <code>T</code> 中指定的属性 <code>K</code>。</p><div class="widget-codetool" style="display: none;">
<div class="widget-codetool--inner">
<button type="button" class="btn btn-dark rounded-0 sflex-center copyCode" data-toggle="tooltip" data-placement="top" data-clipboard-text="interface Person {
name: string;
age: number;
address: string;
}
type PersonWithoutAddress = Omit<Person, "address">;" aria-label="复制" data-bs-original-title="复制">
<i class="far fa-copy"></i>
</button>
</div>
</div><pre class="typescript hljs language-typescript"><span class="hljs-keyword">interface</span> <span class="hljs-title class_">Person</span> {
<span class="hljs-attr">name</span>: <span class="hljs-built_in">string</span>;
<span class="hljs-attr">age</span>: <span class="hljs-built_in">number</span>;
<span class="hljs-attr">address</span>: <span class="hljs-built_in">string</span>;
}
<span class="hljs-keyword">type</span> <span class="hljs-title class_">PersonWithoutAddress</span> = <span class="hljs-title class_">Omit</span><<span class="hljs-title class_">Person</span>, <span class="hljs-string">"address"</span>>;</pre><p>在上面的示例中,<code>Omit<Person, "address"></code> 返回了一个新类型 <code>PersonWithoutAddress</code>,该类型排除了 <code>Person</code> 接口中的 <code>address</code> 属性。</p><h4><code>Readonly<T></code></h4><p><code>Readonly<T></code> 是 TypeScript 中的另一个内置泛型函数,它将类型 <code>T</code> 中的所有属性转换为只读属性。</p><div class="widget-codetool" style="display: none;">
<div class="widget-codetool--inner">
<button type="button" class="btn btn-dark rounded-0 sflex-center copyCode" data-toggle="tooltip" data-placement="top" data-clipboard-text="interface Person {
name: string;
age: number;
}
type ReadonlyPerson = Readonly<Person>;" aria-label="复制" data-bs-original-title="复制">
<i class="far fa-copy"></i>
</button>
</div>
</div><pre class="typescript hljs language-typescript"><span class="hljs-keyword">interface</span> <span class="hljs-title class_">Person</span> {
<span class="hljs-attr">name</span>: <span class="hljs-built_in">string</span>;
<span class="hljs-attr">age</span>: <span class="hljs-built_in">number</span>;
}
<span class="hljs-keyword">type</span> <span class="hljs-title class_">ReadonlyPerson</span> = <span class="hljs-title class_">Readonly</span><<span class="hljs-title class_">Person</span>>;</pre><p>在上面的示例中,<code>Readonly<Person></code> 将 <code>Person</code> 接口中的所有属性变为只读属性,创建了一个新类型 <code>ReadonlyPerson</code>。</p><h3 id="item-1-4">总结</h3><p>泛型和类型体操是 TypeScript 中强大的类型系统的关键组成部分。通过使用泛型,我们可以创建可重用、灵活和类型安全的代码。内置泛型函数提供了一些常用的类型转换工具,如 <code>Partial</code>、<code>Required</code> 和 <code>Pick</code>,可以帮助我们更方便地处理类型操作。</p><p>通过结合泛型、<code>extends</code> 关键字、内置泛型函数和其他高级类型概念,我们能够在 TypeScript 中编写更复杂、类型安全的代码,并利用 TypeScript 的强大类型系统来提高代码的可读性、可维护性和可扩展性。</p>