我想要“实用”的 createModel 函数,它可以推断类型,并且在我使用它时不需要编写类型。
// - here A extends (s: S, p?: any) => S - we want to return our "model" type as result
export function createModel<S, A extends (s: S, p?: any) => S>({
model,
actions,
}: {
model: S,
actions: A
}) {
return {
model,
actions
}
}
type TModel = {
name: string
isActive: boolean
}
const model: TModel = {
name: '',
isActive: false
}
const R = createModel({
model: model,
actions: (model, p) => ({ // - model is TModel model here and its what i expect.
...model,
meta: p, // - here i return invalid model field, and haven't error, i expect TypeError
}),
})
// if i delete spread, it's works - i have TypeError
const R = createModel({
model: model,
actions: (model, p) => ({ // - Type '{ meta: any; }' is missing the following properties from type 'TModel': name, isActive
meta: p,
}),
})
// if try to return primitive (for example - number), it's works - i have TypeError
export function createModel<S, A extends (s: S, p?: any) => number>({ ......
const R = createModel({
model: model,
actions: (model, p) => ({ // - Type '{ meta: any; name: string; isActive: boolean; }' is not assignable to type 'number'.
...model,
meta: p,
}),
})
在“action”函数中,我有这个函数返回的类型,这不依赖于 createModel 中指定的类型。
在“action”函数中,我返回了我在 createModel 函数的泛型中定义的类型。
答案 0 :(得分:0)
这与 Typescript 的工作方式有关。 Typescript 不会检查对象是否完全是您想要的类型,而是检查它是否与您想要的类型兼容。
假设我们有这个接口:
interface IFoo {
boo: string;
loo: number;
}
任何具有字符串属性 boo
和数字属性 loo
的对象,对于 Typescript 来说都是 IFoo
类型。
例如:
// This works
const obj1: IFoo = {
boo: "Bla bla",
foo: 2
}
// This works too (we just added a property, so it's still compatible)!
const obj2: IFoo = {
boo: "Bla bla",
foo: 2,
goo: [1,2,3]
}
// This doesn't work though (Missing property)!
const obj3: IFoo = {
boo: "Bla bla"
}
在这里,您实际上所做的是创建了一个具有 model
属性和额外属性 meta
的对象。因此,Typescript 正确地不会抛出 TypeError 因为类型是兼容的(就像前面提到的 obj2
一样)。
const R = createModel({
model: model,
actions: (model, p) => ({ // - model is TModel model here and its what i expect.
...model,
meta: p, // - here i return invalid model field, and haven't error, i expect TypeError
}),
})
如果您想实现它,有一种解决方法可以实现您想要的(以及对此功能的解释)here:
type ValidateStructure<T, Struct> =
T extends Struct ?
Exclude<keyof T, keyof Struct> extends never ? T : never : never;
export function createModel<S, T extends S>({
model,
actions,
}: {
model: S,
actions: (s: S, p?: any) => ValidateStructure<T, S>
}) {
return {
model,
actions
}
}
我们还应该说,您不需要定义额外的通用类型 A。您可以将类型直接放在您的界面上。
export function createModel<S>({
model,
actions,
}: {
model: S,
actions: (s: S, p?: any) => S
}) {
return {
model,
actions
}
}