我正在嘗試創建一個以字串 Union 作為型別引數的介面。它有兩個孩子,都與聯盟有關。這個想法是它們通過型別引數相互協調。
這是一個簡單的重現:
interface IOptions<TValue extends string> {
values: {[key in TValue]: string};
items: IItem<TValue>[];
}
interface IItem<TValue extends string> {
value: TValue;
}
function printOptions<TValue extends string>(options: IOptions<TValue>) {
console.log(options);
}
printOptions({
values: {a: 'a', b: 'b'},
items: [
{ value: 'a'}
]
});
https://www.typescriptlang.org/play?#code/JYOwLgpgTgZghgYwgAgJIHkAOZgHsQDOAPACoBqcANgK4oQAekIAJgcgWFKAOYB8yAbwBQyZADcqtAgC5BAbQDWEAJ7JQycpIgBdWRy4huAXwDcItZAC2MtKiukKNCLznazRoaEixEKVHYhLBy1kBiZWdk4efmFRCSdZTSd3ISEYahAEHHxkTAMwLGzCYKdQxggWNn1ogApcbDxCWQwG-GIk2l4ASkFzBDbcSggAOkpcbjrWwi6UoTyvQsaCGtjxLRsBOFkAcjhtgBpkACMdo 2jffNgKxs5c1EBNYTkXfPzbSEjGaA
此代碼產生以下錯誤:
Type '{ a: string; b: string; }' is not assignable to type '{ a: string; }'.
我對會發生什么的猜測是打字稿決定items陣列將是定義通用聯合的子元素,然后抱怨values具有未知屬性。
我的問題是,我可以以某種方式使打字稿values用作“聯合定義者”型別嗎?或者以其他方式使它values可以有沒有出現在items?
uj5u.com熱心網友回復:
您只需要推斷引數的每個鍵和值。考慮這個例子:
interface Option<Values, Items> {
values: Values;
items: Items;
}
type Item<Value extends PropertyKey> = { value: Value }
function printOptions<
Value extends string,
Values extends Record<Value, Value>,
InferedItem extends Item<keyof Values>,
Items extends InferedItem[]
>(options: Option<Values, Items>) {
}
printOptions({
values: { a: 'a', b: 'b' },
items: [
{ value: 'a' }
]
});
printOptions({
values: { a: 'a', b: 'b' },
items: [
{ value: 'c' } // error
]
});
操場
將其視為型別銷毀。如果你想推斷每個值,你應該解構它。換句話說,從下到上創建結果型別。
首先,你需要推斷
key/value的values廣告載體:Value extends string然后,您需要推斷整個
values屬性:Values extends Record<Value, Value>與專案相同的方法。您需要推斷一項:
InferedItem extends Item<keyof Values>然后您可以推斷所有專案:
Items extends InferedItem[]
有興趣的Type Inference on function arguments可以看看我的文章
如果要禁止使用陣列中的values鍵items,則需要提供驗證型別助手。您可以在我的文章/博客中找到更多解釋和示例。
interface Option<Values, Items> {
values: Values;
items: Items;
}
type Item<Value extends PropertyKey> = { value: Value }
type Check<
Values extends Record<string, string>,
Items extends Array<any>,
Cache extends Array<any> = []
> =
Items extends []
? Cache
: Items extends [infer Head, ...infer Tail]
? Head extends Item<infer Value>
? Value extends keyof Values
? Check<Values, Tail, [...Cache, Item<never>]>
: Check<Values, Tail, [...Cache, Item<Value>]>
: 1
: Items;
function printOptions<
Value extends string,
ItemValue extends string,
Values extends Record<Value, Value>,
InferedItem extends Item<ItemValue>,
Items extends InferedItem[],
>(options: Option<Values, Check<Values, [...Items]>>) {
}
printOptions({
values: { a: 'a', b: 'b' },
items: [
{ value: 'c' }, // ok
{ value: 'a' }, // error
]
});
操場
Validation algorithm: iterate through items tuple and check every value whether it extends any key from values. If yes - replace value:char with value:never, otherwise don't do anything with item.
Check returns validated items tuple which is used as a second argument for Options. Now, we ended up with a tuple, where each invalid value is replaved by never. SInce never is unrepresentable it is highlighted by TS compiler.
uj5u.com熱心網友回復:
在查看了船長 yossarian 的解決方案后,我想出了這個,在我的情況下效果更好。
type IValuesLookup = {[key: string]: string};
type StringKeys<T> = keyof T extends string ? keyof T : never;
interface IOptions<TValues extends IValuesLookup, TItem extends IItem<StringKeys<TValues>>> {
values: TValues;
items: TItem[];
}
interface IItem<TValue extends string> {
value: TValue;
}
function printOptions<TValues extends IValuesLookup, TItem extends IItem<StringKeys<TValues>>>(options: IOptions<TValues, TItem>) {
console.log(options);
}
printOptions({
values: {a: 'a', b: 'b'},
items: [
{ value: 'a'}
]
});
https://www.typescriptlang.org/play?#code/C4TwDgpgBAkgagQwDYFcIGcAyB7bBrFMKAXigG8BtPCEALinWACcBLAOwHMBdex1zgL4BuAFChIUAMrN2HANI10AHgAqAPhJRqIbADMoKqBAAewCGwAm6BjM5QA-Fpp6DUemwgA3CE1Ej2Zky6CADG0DAA8mDALNhsyiqIqBhGpuZWsEloWLgEYAA0BjBmALapZpbWMMUQJUrS-PKKqlkYau3kIlBQnsjZ9Il9GKLdLKXoAzUlFFyiAv5sgcFhsFMtQ Xp1nyyGmRdPUMDrXMiIroobCExcVBg-MBRN-HrydYmFRnwQzn4hIUqKabSqrUr1WxNEAJVrodpqAAU2GisXi9EiyLi0J AKmagAlJ1uiFMdgkBAAHRIbAcREY J404ie4BJ4o9Dw-bdXpvehkBD0ADkCAFhQARoLRQKBPkDmNahMoBQDt0yIdkoLhfNulwRAIGUA
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/335833.html
上一篇:密封類泛型
下一篇:通用有界引數與自身不兼容
