Reputation: 617
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", 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.
Edit: The question was not clear.
To clarify, the problem is that when you infer the arguments to noGood
, the Prefix
inferrence does not work as desired (but not necessarily unexpected) since it would be ideal to have the Prefix
constrained to the generic Prefix
of obj
(the first argument).
In this example, Prefix
(generic) is literally 'prefix'
and it would be desired to only allow that for the noGood
second argument that is inferred. However, when you call noGood(obj, 'diff-prefix')
the Prefix
generic becomes 'prefix' | 'diff-prefix'
and ideally it would be constrained to the inferred type from obj
rather than the inferred type from the union of the first and the second argument.
Hope that clears things up. Can definitely see how it was unclear.
Upvotes: 0
Views: 45
Reputation: 11581
@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.
Upvotes: 1
Reputation: 11581
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
.
Upvotes: 0