-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Exclude not work on [key: string]:any #31153
Comments
There are ways of extracting the literal keys if you need to do it. I'd say this issue is a duplicate but I'm not sure which issue it duplicates. What issues do you think are related? Hmm, looks like you didn't actually search for it (since your "search terms" are empty). Oh well. |
@jcalz Have you try your solution? No you didn't. it not work. Though it is the true solution to get a known key such as 'a' and 'b' in the example, this is not my finally target. My target is to produce a new type witch include key 'b' but not 'a' and any other unknown string key. In a word, I need a perfect
|
@vipcxj Let's keep discussions polite and constructive. @jcalz was giving you the starting point for a solution, not a complete solution. To actually get it to work, you first have to type KnownKeys<T> = {
[K in keyof T]: string extends K ? never : number extends K ? never : K
} extends {[_ in keyof T]: infer U} ? U : never;
interface TestType {
a: number;
b: string;
[key:string]: any;
}
// A bit of arm wrestling to convince TS KnownKeys<T> is keyof T
type OmitFromKnownKeys<T, K extends PropertyKey> = KnownKeys<T> extends infer U ?
[U] extends [keyof T] ? Pick<T, Exclude<U, K>>:
never : never;
type OmitOnIndexed<T, K extends PropertyKey> =
OmitFromKnownKeys<T, K> & // Get the known part without K
(string extends keyof T ? { [n: string]: T[keyof T]} : {}) // Add the index signature back if necessary
const test:OmitOnIndexed<TestType, 'a'> = { } // error Note The solution above might not work as expected once we get any type in index signatures. But we can deal with that when it ships :) |
@dragomirtitian thanks, it partially works. I don't know whether it is the most perfect Omit version, it is the most perfect Omit version I have seen. type KnownKeys<T> = {
[K in keyof T]: string extends K ? never : number extends K ? never : K
} extends { [_ in keyof T]: infer U } ? ({} extends U ? never : U) : never; // I don't know why not just U work here, but ({} extends U ? never : U) work
type OmitFromKnownKeys<T, K extends keyof T> = KnownKeys<T> extends infer U ?
[U] extends [keyof T] ? Pick<T, Exclude<U, K>>:
never : never;
type Omit<T, K extends keyof T> = OmitFromKnownKeys<T, K>
& (string extends K ? {} : (string extends keyof T ? { [n: string]: T[Exclude<keyof T, number>]} : {})) // support number property
& (number extends K ? {} : (number extends keyof T ? { [n: number]: T[Exclude<keyof T, string>]} : {})) // support number property It is very very complicate. and I still not sure it is the perfect version. I think the perfect version Omit function should be built in. |
@vipcxj Typescript tends to offer the building blocks to build such types, they also tend not to include very complicated types in the base lib (the relatively simple Your version includes The root problem is that there isn't a good way to get the index signature out of a type and to differentiate known keys from the index signature. While this solution works, I do believe it might break in the future (not necessarily break for existing code, but not work with new features). This is also a very good point against including it in the base lib |
@dragomirtitian what I mean is not including it in lib but include it in the syntax level or some native level. Omit is the very very often used type, and it even tightly bind to some syntax, such as the following example. But I haven't seen such a compete version before, even the official version is incomplete. interface TestType {
a: number;
b: string;
[key:string]: any;
}
const test: TestType = { a: 1, b: 'test', c: {}, d: 1 }
const { a, ...rest } = test // it seems that typescript think the type of rest is {}. and auto complete hints of rest show nothing. Its type should be Omit<TestType, 'a'>. this should be a very base feature. |
As reported in #44143 typescript 4.3 broke the I've tried fixing its implementation and I came up with a solution with a small caveat, though: type KnownKeys<T> = {
[K in keyof T as string extends K
? never
: number extends K
? never
: K]: T[K];
};
type OmitFromKnownKeys<T, K extends keyof T> = KnownKeys<T> extends infer U ?
keyof U extends keyof T
? Pick<T, Exclude<keyof U, K>> & Pick<T, Exclude<keyof T, keyof KnownKeys<T>>>
: never : never; While this is generally working, it resolves to a type like type Test = {
[x: number]: any,
[y: string]: any,
a: number,
b: string,
c: string,
}
// resolves to:
// const test: Pick<Test, "b" | "c"> & Pick<Test, string | number>
// instead of:
// const test: {
// [x: string]: any;
// [x: number]: any;
// a: string;
// }
const test: OmitFromKnownKeys<Test, "b" | "c"> = {
a: 42,
[0]: 21,
["something"]: "test",
} Does anyone have an idea for how to make this resolve to the object type instead without losing the known keys? |
Just a friendly bump, because I found a similar situation in my code. I also found that you can remove the index signature (as shown here), // Returns a type with the same well-known props, but without the index signature
type NoIndex<T> = {
[K in keyof T as {} extends Record<K, 1> ? never : K]: T[K]
}
// Inverse of NoIndex, meaning it only gets the index signature of a type, ignoring other well known props
type OnlyIndex<T> = {
[K in keyof T as {} extends Record<K, 1> ? K : never]: T[K]
}
// Omit from NoIndex version of T, and then intersects with the indexed part of it
type OmitFromKnownKeys<T, K extends keyof NoIndex<T>> = Omit<NoIndex<T>, K> & OnlyIndex<T>
type type Test = {
[x: number]: any,
[y: string]: any,
a: number,
b: string,
c: string,
}
type TestOmitted = OmitFromKnownKeys<Test, 'b' | 'c'> |
@felschr You could use Any.Compute util type from https://github.com/millsp/ts-toolbelt to provide a better display. I have extracted the code there and made an example, based on #31153 (comment) by @augustobmoura. |
Edit: looks like this is the same suggestion as #54451! I stumbled upon this simple type which I think solves the Omit problem in this thread:
As @jcalz mentioned, trying to separate out the "known" keys from the union is really hard. But we can dodge this problem altogether. Using key remapping, we can map over and I made an example based on @whzx5byb's example above. This doesn't really solve the |
TypeScript Version: 3.4.4
Search Terms:
Code
Expected behavior:
show missing b error
Actual behavior:
no error
Playground Link:
Related Issues:
The text was updated successfully, but these errors were encountered: