0

For example, how can we extract only the keys that have string types? Here is what I have tried:

type StringEntriesOnly<T> = {
    [K in keyof T]: T[K] extends string ? T[K] : never;
}

type SomeType = {
    aString: string;
    aNumber: number;
}

const v1: StringEntriesOnly<SomeType> = {
    aString: 'Hello',
    aNumber: 10, // This is a compiler error. Good. 
}

type StringKeys = keyof StringEntriesOnly<SomeType>;

const v2: StringKeys = 'aNumber'; // How can we make the compiler complain here?

In the above example, I would like StringKeys to allow only 'aString'.

Shaun Luttin
  • 133,272
  • 81
  • 405
  • 467

1 Answers1

1

I usually define KeysMatching like this

type KeysMatching<T, V> = { [K in keyof T]-?: T[K] extends V ? K : never }[keyof T];

(the -? avoids some pitfalls with optional properties while introducing other pitfalls; check edge cases)

That gives you

type StringKeys = KeysMatching<SomeType, string>;
// type StringKeys = "aString"

const v2: StringKeys = 'aNumber'; // error!

Hope it helps. Playground link

jcalz
  • 264,269
  • 27
  • 359
  • 360
  • Why bother with the `-?`? `KeysMatching` works without that. – Shaun Luttin Jun 04 '20 at 01:48
  • 1
    If your `SomeType` has optional properties you can get weirdness without it. Try making `aNumber` optional and see what happens. The `undefined` bleeds out into the answer. – jcalz Jun 04 '20 at 01:50
  • Like [this](https://www.typescriptlang.org/play/#code/C4TwDgpgBA0hIGcCyBDYBjAFgSwHYHMAeAFQBooA1APigF4oBvKAbRijygGt4B7AMyjEAugC5BrIVAgAPYBFwATBJSgB+WFDG4IANwgAnKAF9m3EP0FCA3ACgboSFADKPALYRi4aPQY2o-qBQnYH08fDEEELDbAMCAOQBXVwAjA1UtJNT9WyM7B2hg0II4RDpYeGQ0LDDCF3dPSHJIovwqWwB6dqh85yjiirKAIiC+-EGoAB8oBMUIPjwIBSgAQlVluyA) – jcalz Jun 04 '20 at 01:50