There are two methods to impose type restrictions on a
:
Type assertion at compile time only
@Qwertiy proposed this solution, which utilizes an interface that extends the never
type in case of a failed type assertion to trigger a compile error. Additionally, a compile error can be generated by using a generic type constraint. By allowing the assertion type to be generic and accept multiple types, it could be implemented as shown below (Playground):
type AssertAssignable<T, U extends T> = true
var a = [{
id: 1,
data: [],
}] as const
var aError = [{
id: "foo",
data: [],
}] as const
type Assert = AssertAssignable<readonly ISmth<any>[], typeof a>
type AssertError = AssertAssignable<readonly ISmth<any>[], typeof aError> // error(OK!)
Type assertion utilizing a helper function (originally from here)
A helper function named createA
can be created with the sole purpose of enforcing types on the object literal created for a
, while still maintaining strict typing via as const
(Playground):
function createA<A extends Readonly<ISmth<any>[]>>(a: A): A {
return a
}
var a = createA([{
id: 1,
data: []
}] as const);
var aError = createA([{
id: "1", // error (OK!)
data: []
}] as const);
You can also perform the assertion inline using an IIFE, if createA
is not used elsewhere:
var aInline = (<A extends Readonly<ISmth<any>[]>>(a: A) => a)([{
id: 1,
data: [],
}] as const)
... or create a versatile utility helper that can be exported.
function enforceTypedLiteral<T>() {
return <A extends T>(a: A) => a
}
enforceTypedLiteral<readonly ISmth<any>[]
>()([{
id: 1,
data: []
}] as const)