Mirza Chilman
Mirza Chilman

Reputation: 429

specify keyof type in typescript

Is there a way to specify the key that are already defined in type?

interface KeyType {
 userName: string,
 address: string
}

type ValidationType = {
 userName: ValidateUserNameType;
 address: ValidateAddressType;
}

Those KeyType and ValidationType is being used for different things but ValidationType key will always be the same as KeyType.

I've been looking around but I got no luck

Upvotes: 0

Views: 85

Answers (2)

ford04
ford04

Reputation: 74490

You could define a custom type that enforces same keys:

type SameKeys<T, U extends Record<keyof T, any>> =
    { [K in keyof U]: K extends keyof T ? U[K] : never }

// e.g.
type SameKeysValidationType = SameKeys<KeyType, ValidationType>

U must extend all keys from T. If U has more properties, they will be resolved to never value type. But this won't throw a compile error yet - two options here:

interface extension

interface ValidationType extends SameKeys<KeyType, ValidationType> {
    userName: ValidateUserNameType;
    address: ValidateAddressType;   // comment => compile error
    // foo: string                  // uncomment => compile error
}

Assertion type

// generic assert type
type AssertSameKeys<T, U extends Record<keyof T, any> & SameKeys<T, U>> = true

// this will error, when ValidationType is not proper
type AssertValidationType = AssertSameKeys<KeyType, ValidationType> 

Above variants will work with your case. You should still evaluate and test, what you want to do with optional properties and other edge cases.

Playground sample here

Upvotes: 1

Maciej Sikora
Maciej Sikora

Reputation: 20132

My proposition here is to create third type which will join these two in the way you want. Consider:


interface KeyType {
    userName: string,
    address: string
}
type ValidationRules = {
    userName: ValidateUserNameType;
    address: ValidateAddressType;
    other: ValidateUserNameType; // this field will not be in ValidationType
}
// Validation type below is not affected by any additional key in ValidationRules
// keys are applied only if are added in KeyType and in ValidationRules
type ValidationType = {
    [K in keyof KeyType]: ValidationRules[K]
}

After that our type ValidationType will always have:

  • keys from KeyType
  • will have an error if there is no rule in ValidationType for a key in KeyType
  • will skip any additional keys from ValidationRules

In other words ValidationType is fully driven by both types, and will have only keys existing in both, any key which not exists in both will be skipped or be an compile error.

Upvotes: 1

Related Questions