Consider the following code
type EnforceNonEmptyValue<TValueArg extends string> = {
value: TValueArg extends '' ? never : TValueArg
type: 'substringMatch'
}
function identity<
TValueArg extends string
>(
object: EnforceNonEmptyValue<TValueArg>
) {
return object
}
// rightfully complaints
identity({value: '', type: 'substringMatch'})
//---------^
// `Type 'string' is not assignable to type 'never'.ts(2322)`
// works
identity({value: 'works', type: 'substringMatch'})
The function identity
with the help of EnforceNonEmptyValue
generic enforces that the object passed to the function has a non empty string value, i.e. the value of value
property should not be an empty string ''
I want to extend this check for an array of objects
identityArray([
{
type: 'substringMatch',
value: 'np-payment',
},
{
type: 'substringMatch',
value: '',
//------^ should complain here
},
])
i.e I want typescript to throw an error if any object in an array of objects has a value
property's value as an empty string ''
But I've been having a hard time to make it work. How could we enforce it for an array of objects? ( with or without an identity function )
You can use a mapped array/tuple type as shown here:
function identityArray<T extends string[]>(
args: [...{ [I in keyof T]: EnforceNonEmptyValue<T[I]> }]
) { }
The compiler can infer the type T
from the homomorphic mapped type (see What does "homomorphic mapped type" mean?) {[I in keyof T]: EnforceNonEmptyValue<T[I]>}
. I wrapped it with a variadic tuple type ([...
+]
) to give the compiler a hint that we'd like T
to be inferred as a tuple type and not as an unordered array type, but you might not care either way.
Anyway, let's test it:
identityArray([
{
type: 'substringMatch',
value: 'np-payment',
},
{
type: 'substringMatch',
value: '', // error!
},
])
// function identityArray<["np-payment", ""]>(
// args: [EnforceNonEmptyValue<"np-payment">, EnforceNonEmptyValue<"">]
// ): void
Looks good. The compiler accepts "np-payment"
and rejects ""
. You can see that T
is inferred as the tuple type ["np-payment", ""]
and the args
argument is of the mapped tuple type [EnforceNonEmptyValue<"np-payment">, EnforceNonEmptyValue<"">]
.