typescript 打字稿动态创建界面
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/45771307/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Typescript dynamically create interface
提问by Chris
I use simple-schema to define DB schemas in an object:
我使用简单模式在对象中定义数据库模式:
{
name: 'string',
age: 'integer',
...
}
Is it somehow possible to create an interface or class from this object, so I don't have to type everything twice?
是否有可能从这个对象创建一个接口或类,所以我不必输入两次?
回答by jcalz
You can do this, but it might be more trouble than it's worth unless you think you might be changing the schema. TypeScript doesn't have built-in ways of inferring types in a way that you want, so you have to coax and cajole it to do so:
您可以这样做,但它可能比它的价值更麻烦,除非您认为您可能正在更改架构。TypeScript 没有以您想要的方式推断类型的内置方法,因此您必须哄骗它这样做:
First, define a way of mapping the literal names 'string'
and 'integer'
to the TypeScript types they represent (presumably string
and number
respectively):
首先,定义映射文字名称的方法'string'
和'integer'
其所代表的打字稿类型(大概string
和number
分别地):
type MapSchemaTypes = {
string: string;
integer: number;
// others?
}
type MapSchema<T extends Record<string, keyof MapSchemaTypes>> = {
[K in keyof T]: MapSchemaTypes[T[K]]
}
Now if you can take an appropriately typed schema object like the one you specified, and get the associated type from it:
现在,如果您可以采用像您指定的那样类型适当的模式对象,并从中获取关联的类型:
const personSchema = {name: 'string', age: 'integer'};
type Person = MapSchema<typeof personSchema>; // ERROR
Oops, the problem is that personSchema
is being inferred as {name: string; age: string}
instead of the desired {name: 'string'; age: 'integer'}
. You can fix that with a type annotation:
糟糕,问题是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};
But now it feels like you're repeating yourself. Luckily there is a way to force it to infer the proper type:
但现在感觉就像你在重复自己。幸运的是,有一种方法可以强制它推断正确的类型:
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};
That works!
这样可行!
See it in action on the Typescript Playground. Hope that helps; good luck!
在 Typescript Playground 上查看它的实际效果。希望有所帮助;祝你好运!
回答by Shane van den Bogaard
I don't think you can declare dynamic interfaces. However, you can create a typefor objects with known properties.
我认为您不能声明动态接口。但是,您可以为具有已知属性的对象创建类型。
You can create an object that maps string literals to actual types, e.g. 'integer' => number
, but that is not relevant to the question. I don't know what framework you're using but the following example works for a similar looking framework: Mongoose.
您可以创建一个将字符串文字映射到实际类型的对象,例如'integer' => number
,但这与问题无关。我不知道您使用的是什么框架,但以下示例适用于外观相似的框架:Mongoose。
users.js
用户.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 } ;
usage:
用法:
import { User, Users } from './user';
Users.find({}).exec((err: Error, res: User) => { ... })
The returned result should have the same keys as UserSchema
, but all values are mapped to any as you would still have to map string literals to types.
返回的结果应该具有与 相同的键UserSchema
,但所有值都映射到 any ,因为您仍然需要将字符串文字映射到类型。