【发布时间】:2017-08-19 12:03:48
【问题描述】:
我使用 simple-schema 在对象中定义 DB 模式:
{
name: 'string',
age: 'integer',
...
}
是否有可能从这个对象创建一个接口或类,所以我不必输入两次?
【问题讨论】:
标签: javascript typescript
我使用 simple-schema 在对象中定义 DB 模式:
{
name: 'string',
age: 'integer',
...
}
是否有可能从这个对象创建一个接口或类,所以我不必输入两次?
【问题讨论】:
标签: javascript typescript
您可以这样做,但除非您认为您可能正在更改架构,否则它可能会带来更多麻烦而不是值得。 TypeScript 没有内置的方法来以您想要的方式推断类型,因此您必须哄骗它这样做:
首先,定义一种将文字名称 'string' 和 'integer' 映射到它们所代表的 TypeScript 类型的方法(大概分别是 string 和 number):
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 assertion 来获得相同的结果:
const personSchema = { name: 'string', age: 'integer' } as const;
type Person = MapSchema<typeof personSchema>;
这行得通!
看到它在行动on the Typescript Playground。希望有帮助;祝你好运!
【讨论】:
const personObj = { name: 'string', age: 'integer' } type Person = MapSchema<typeof asSchema(personObj)>; 我在封装这个方面非常不成功。
as-clauses-in-mapped-types 会有所帮助,但我们没有。
我认为您不能声明动态接口。但是,您可以为具有已知属性的对象创建type。
您可以创建一个将字符串文字映射到实际类型的对象,例如'integer' => number,但这与问题无关。我不知道您使用的是什么框架,但以下示例适用于外观相似的框架:Mongoose。
users.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 具有相同的键,但所有值都映射到任何值,因为您仍然必须将字符串文字映射到类型。
【讨论】:
User) 包含 javascript 对象 (UserSchema) 的 每个 键?
MapSchema util 的东西,但我没有使用任何类型的真实数据库模式,我只有一个简单的字段名称对象及其默认值.我不喜欢使用 { [K in keyof Thing]: string } 语法,因为我想断言我的“模式”的 每个 键都是针对创建的类型强制执行的 - 我可以在这里回答我自己的问题:@987654322 @