Home > OS >  Is it possible to contrain inferred generics in typescript?
Is it possible to contrain inferred generics in typescript?

Time:09-25

Take the following example:

type A<Keys extends string, Prefix extends string> = 
  {[K in Keys]: `${Prefix}-${K}`}

function noGood<K extends string, Prefix extends string>(
  obj: A<K, Prefix>, prefix: Prefix
) {
// ...
}

const test: A<'one' | 'two', 'prefix'> = {"one": 'prefix-one', "two": 'prefix-two'}

noGood(test, 'desired to only be "prefix-one" or "prefix-two", but can be any string...')

You can see that the generic types of noGood are inferred from the first param (obj). Then, when you provide a string to the second param (prefix)

Obviously you could type out your call to noGood and it would disallow that random string for the second parameter, but ideally you wouldn't have to.

CodePudding user response:

@HelloWorld per your comment on my other answer, if you want the parameter prefix to only be a value at one of the keys of the object, it is still relatively easy with some tweaks:

const foo = {"one": 'prefix-one' as const, "two": 'prefix-two' as const}

function noGood<O extends {}>(
  obj: O, prefix: O[keyof O]
) {
// ...
}

noGood(foo, 'prefix-one'); // sure ok
noGood(foo, 'crabapple'); // error!

Note the use of as const when defining the values inside of foo. This is important because it tells TypeScript that those are values will not change and can be treated as a constant, explicit type and not just any old string. Otherwise, noGood(foo, 'crabapple') would not give an error because TypeScript normally would infer the values at each key of foo as a string and not "prefix-one" | "prefix-two".

If this still doesn't meet your use case, please update your question with more specific details and requirements.

CodePudding user response:

This is trivial at a basic level if you don't care too much about constraining the object parameter of "noGood()". Use generics to enforce that the parameter prefix is a key of the object parameter obj (the word "prefix" seems like a misnomer here since you seem to only care about the keys of obj but I digress):

function noGood<O extends{}>(
  obj: O, prefix: keyof O
) {
// ...
}

There is not really a way that I know of to extract the type information for "Prefix" from your type A because that generic type information is not retained by the object after you instantiate it -- there is just no way to enforce that the object passed in as obj is definitely an instance of your type A.

  • Related