使用新的索引as語法,我可以過濾掉一個型別的鍵,如下所示。
// Filter out all keys of `T` that do not exist in `U`
type IntersectKeys<T, U> = {
[K in keyof T as K extends keyof U ? K : never]: T[K];
};
// e.g., IntersectKeys<{ foo: string; bar: number}, { foo: never }> === { foo: string }
但是,當我將此型別與泛型一起使用時,TypeScript 似乎完全忽略了型別檢查。
這是 TypeScript 錯誤嗎? 有沒有解決的辦法?
interface FooBar {
foo: string;
bar: number;
}
function intersectFooBarKeys<U>(fb: FooBar, intersect: U): IntersectKeys<FooBar, U> {
return false; // ---> !!Wrong implementation, but no type error!! <---
}
// Example usage
const fooBar: FooBar = {
foo: 'foo',
bar: 42,
};
const onlyFoo: { foo: string } = intersectKeys(fooBar, { foo: null });
// Based on its type, I would expect `onlyFoo` to be of the form `{ foo: string }`, but it is `false` instead!
uj5u.com熱心網友回復:
這似乎是 TypeScript 中的錯誤或設計限制。編譯器無法對高階型別操作(如對泛型型別的鍵重映射)進行太多推理。圍繞通用密鑰重新映射有幾個 GitHub 問題,例如ms/TS#45212 和ms/TS#48855和ms/ TS#47447 ,但我沒有看到任何特定于這個特定問題的內容。有人可能會用這樣的代碼提交一個新問題作為復制:
type Foo<U> = {
[K in "foo" | "bar" as Extract<K, keyof U>]: 1;
};
type X = Foo<{ foo: 0, baz: 0 }> // {foo: 1}
type Y = Foo<{ baz: 0, qux: 0 }> // {}
type Z = Foo<{ [k: string]: 0 }> // {foo: 1, bar: 1}
function generic<U extends { [k: string]: 0 }>() {
type G = Foo<U> // {} <-- shouldn't this either be *deferred* or,
// if anything, eagerly resolved to {foo: 1, bar: 1}?
}
但我不知道會發生什么。
一般來說,當編譯器看到任何型別的涉及泛型型別引數的復雜型別函式時,它可以決定推遲對它的評估,從而將其視為不透明的型別,沒有任何可分配的......或者它可以決定過早地評估它通過用與之相關的東西替換泛型型別引數......從而可能將其解決為不正確的東西。看起來后者就是這里發生的事情;不管是什么U,K extends keyof U ? K : never都被過早地歸結為never重新映射子句內部,因此您將IntersectKeys<FooBar, U>獨立{}于U. 這尤其不幸,因為{}是特殊情況,不會觸發過多的屬性檢查(請參閱其他答案),等等,除了andfalse之外的任何東西都可以分配給它。哎呀。nullundefined
因此,我會說這個問題類似于microsoft/TypeScript#24560中的問題。我們正在嘗試使用條件型別來過濾與泛型型別相關keyof的泛型型別,而編譯器無法弄清楚這可能是什么。該問題的可操作評論說:
給定一個任意約束
T extends C,對于任何可能的實體化,幾乎沒有什么事情可以很容易地確定T——您不能只C按原樣使用并從另一方得到正確的答案。T當作為子型別關聯時,我們有一些邏輯,但是一旦你進行了像 的逆變操作keyof T,所有的賭注都沒有了。
無論如何,對于您的示例代碼,我的方法是盡可能堅持使用非條件非重新映射型別,因為編譯器在那里具有更好的推理能力(或至少推遲它們):
type IntersectKeys<T, U> = Pick<T, keyof T & keyof U>
這表現得如所愿,或者至少推遲評估,以便類似false的東西不被視為可分配給它:
function intersectFooBarKeys<U>(fb: FooBar, intersect: U): IntersectKeys<FooBar, U> {
return false; // error! Type 'boolean' is not assignable to type 'IntersectKeys<FooBar, U>'
}
Playground 代碼鏈接
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/495759.html
下一篇:選擇器陣列php來刺痛
