打字稿动态创建界面



我使用简单模式来定义对象中的数据库模式:

{
name: 'string',
age: 'integer',
...
}

是否可以以某种方式从此对象创建接口或类,这样我就不必键入所有内容两次?

您可以这样做,但除非您认为可能要更改架构,否则可能会比它的价值更麻烦。 TypeScript 没有以您想要的方式推断类型的内置方法,因此您必须哄骗和哄骗它这样做:


首先,定义一种将文字名称'string''integer'映射到它们所表示的 TypeScript 类型(大概分别为stringnumber(的方法:

type MapSchemaTypes = {
string: string;
integer: number;
// others?
}
type MapSchema<T extends Record<string, keyof MapSchemaTypes>> = {
-readonly [K in keyof T]: MapSchemaTypes[T[K]]
}

现在,如果可以采用适当类型的架构对象(如指定的模式对象(,并从中获取关联的类型:

const personSchema = {name: 'string', age: 'integer'}; 
type Person = MapSchema<typeof personSchema>; // ERROR

糟糕,问题是personSchema被推断为{name: string; age: string}而不是所需的{name: 'string'; age: 'integer'}. 您可以使用类型注释来解决此问题:

const personSchema: { name: 'string', age: 'integer' } = { name: 'string', age: 'integer' }; 
type Person = MapSchema<typeof personSchema>; // {name: string; age: number};

但现在感觉就像你在重复自己。 幸运的是,有一种方法可以强制它推断正确的类型:

function asSchema<T extends Record<string, keyof MapSchemaTypes>>(t: T): T {
return t;
}
const personSchema = asSchema({ name: 'string', age: 'integer' }); // right type now
type Person = MapSchema<typeof personSchema>; // {name: string; age: number};

更新 2020-06:在较新的 TS 版本中,您可以使用const断言来获得相同的结果:

const personSchema = { name: 'string', age: 'integer' } as const;
type Person = MapSchema<typeof personSchema>;

那行得通!


在 Typescript Playground 上查看它的实际效果。 希望有帮助;祝你好运!

我认为你不能声明动态接口。但是,您可以为具有已知属性的对象创建类型。

您可以创建一个将字符串文本映射到实际类型的对象,例如'integer' => number,但这与问题无关。我不知道你使用的是什么框架,但以下示例适用于外观类似的框架:猫鼬。

用户.js

export const UserSchema = mongoose.Schema({
name: String,
value: Number
});
export const Users = mongoose.Model('users', UserSchema);
export type User = { [K in keyof typeof UserSchema]: any } ;

用法:

import { User, Users } from './user';
Users.find({}).exec((err: Error, res: User) => { ... })

返回的结果应该与UserSchema具有相同的键,但所有值都映射到 any,因为您仍然必须将字符串文字映射到类型。

最新更新