Así que tengo un tipo de unión de cadenas
type S = 'a' | 'b' | 'c';Quiero inicializar un valor de tipo S, mientras afirmo que es de tipo S. Con una variable, es muy fácil:
const s1: S = 'a'; const s2: S = 'z'; // error Sin embargo, solo quiero instanciar el valor en sí mismo, en la línea de 'a' as S pero comprobando que 'a' es de tipo S .
El caso de uso exacto es que estoy usando una biblioteca que proporciona una función f(s: string) , pero quiero asegurarme de que cuando la llame, solo la llame con las cadenas que considero correctas. Dado que [afaik] no puede restringir la firma desde fuera de la biblioteca, estaba pensando en hacer algo como f('a' as S) cada vez que usaba f .
Definir mi propia función g = (s: S) => f(s) no es una gran opción porque en realidad la firma de f se parece a f(s: string, t: T) donde T es un tipo complejo definido por biblioteca que no estoy seguro es incluso exportado.
¿Cuál sería la mejor manera de lograr esto?
Envuelva la función externa con la suya usando el tipo de cadena ( TS playground ):
const externalFn = <T>(s: string, t: T) => t type S = 'a' | 'b' | 'c'; const yourFn = (s: S, t: Parameters<typeof externalFn>[1]) => externalFn(s, t)Si necesita manejar una función con más de un argumento, puede usar la idea en esta respuesta ( TS playground ):
type DropFirst<T extends unknown[]> = T extends [any, ...infer U] ? U : never const externalFn = <T>(s: string, t: T) => t type S = 'a' | 'b' | 'c'; const yourFn = (s: S, ...rest: DropFirst<Parameters<typeof externalFn>>) => externalFn(s, ...rest)Terminé haciendo una función contenedora simple así:
function ok<T extends string>(s: T): T { return s; } que luego podría usar como f(ok<S>('a')) , porque en mi caso había múltiples funciones y tipos para los que quería hacer esta verificación, y hacer una función de envoltura separada sería tedioso y no mantenible .