类orm模型的enum类型推断



我有一个enum DataType { NUMBER, STRING }和一个对象const example: Record<string, DataType> = { id: DataType.NUMBER, name: DataType.STRING }

我希望TypeScript理解example.idnumber(而不是DataType.NUMBER),example.name通过通用的converter()函数被视为string而不是DataType.STRING

不需要实现该函数,只需要根据传递给它的参数进行type推理:

function converter(...): infer type here { ... }
const example = converter({ id: DataType.NUMBER, name: DataType.STRING });
ts.typeof example.id === number
ts.typeof example.name === string

我的目标是用户应该传递一个数据模型("模式"),函数将返回一个与数据模型兼容的值,类似于ORM。

class Model {
public get(... columns: string[]) {
// ...
}
}
class User extends Model {
public columns: {
id: DataType.NUMBER,
name: DataType.STRING,
age: DataType.NUMBER
}
}
const user = new User.get("id", "name")
ts.typeof user === { id: number, name: string }

编辑# 1:作为补充,在现实中,我可以很容易地得到这样的结果:

function convert<T extends Record<string, DataType>>(schema: T) {
return {} as ConvertedType = { [K in keyof T]: T[K] extends DataType.NUMBER ? number : T[K] extends DataType.STRING ? string : never };
}

虽然它工作得很好,但它在更复杂的代码中不起作用,比如:

interface Schema {
[k: string]: DataType
}
type SchemaReturn<S extends Schema, C extends keyof S> = {
[K in C]: S[K] extends DataType.NUMBER ? number : S[K] extends DataType.STRING ? string : never;
};
abstract class Model {
public schema: Schema = {};

public select<C extends keyof this["schema"]>(... columns: C[]) {
return {} as SchemaReturn<typeof this["schema"], C>;
}
}
class User extends Model {
public schema = {
id: DataType.NUMBER,
name: DataType.STRING,
age: DataType.NUMBER
}
}
const user = new User;
const data = user.select("id", "name");
data.id; // Must be `number` but got `never`
data.name; // Must be `string` but got `never`

我得到了一个非常接近我想要的结果,尽管用const取代了enum并产生了一定的"陌生感";schema属性的类型:

const DataType = {
NUMBER: 0,
STRING: 1,
} as const;
interface Schema {
[k: string]: typeof DataType[keyof typeof DataType];
}
type SchemaReturn<S extends Schema, C extends keyof S> = {
[K in C] 
: S[K] extends typeof DataType.NUMBER ? number
: S[K] extends typeof DataType.STRING ? string
: never;
};
class User extends Model {
public schema = {
// And here are the odd ones:
id: DataType.NUMBER, // ts.typeof id === 0 (but expected to keeped DataType.NUMBER)
name: DataType.STRING, // ts.typeof id === 1 (but expected to keeped DataType.STRING)
age: DataType.NUMBER, // ts.typeof id === 0 (but expected to keeped DataType.NUMBER)
};
}
// ...
// But here I get exactly the result I would like:
data.id; // ts.typeof data.id === number
data.name; // ts.typeof data.name === string

我愿意接受新的建议,因为我想继续使用enum而不是JSconst

相关内容

  • 没有找到相关文章

最新更新