打字稿:扩展接口并将现有字段重新声明为只读

Typescript: extending an interface and redeclaring the existing fields as readonly

假设我们有这样一个界面:

interface Person {
  name: string;
  age: number;
}

我想调用 Readonly 并创建接口的只读版本,例如

interface PersonReadonly extends Readonly<Person> {}

相当于写

interface PersonReadonly {
  readonly name: string;
  readonly age: number;
}

能不能写这样一个Readonly泛型接口,还是已经写好了?

TypeScript 2.1 开始,用于制作实例 readonly 的所有字段的通用接口可用。

它的名字恰好是 Readonly<T>,因此您可以这样使用它:

let person: Readonly<Person> = { name: 'John', age: 30 };
person.age = 31; // gives error

在 TypeScript 2.1 之前不可能实现泛型只读类型。

在 playground 中定义了 Readonly 类型,因此您可以:

interface Person {
    name: string;
    age: number;
}

let a: Readonly<Person> = {
    name: "name",
    age: 3
};

a.age = 5; // Error: Cannot assign to 'age' because it is a constant or a read-only property

(code in playground)

如果在您的环境中定义了该类型,那么您可以简单地添加它:

type Readonly<T> = {
    readonly [P in keyof T]: T[P];
}

但它要求你有 typescript 2.1 及以上版本。
如果你没有,那可能是你的typescript版本低于2.1,否则你可以直接使用。

回答你明确的问题:从技术上讲,你还不能做你想做的事。

类型映射将创建一个 Type 而不是接口 -- Readonly<T> 是一个内置的类型映射器,它将 return 一个 Type。您不能实现或扩展 Type 别名,只能实现或扩展接口 / class。

因此:

interface PersonReadonly extends Readonly<Person> {}

support for implementing types are done 之前无效,如果有的话。

但这并不能阻止您传递 Type;您也可以在类型上使用 union 来构建更复杂的类型。因此你可以这样做:

type PersonWithState = Readonly<Person> & { state: string }

let person = <Person>{ name: "John", age: 20 };
let personState = <PersonWithState>{ ...person, state: "online" };

personState.age = "30"; // error;
personState.state = "offline"; // OK.

但是您还不能 class 实现或扩展接口,PersonWithState

你可以这样做:

type PersonReadonly = Readonly<Person>

但它不是一个接口。例如,您不能在其他地方添加新成员。

2017 年 5 月编辑:自 TS 2.2(2017 年 2 月)起,interfaces can be derived from types.