No tengo ni idea de si esto es posible o incluso aconsejable. Estoy tratando de usar una propiedad en un tipo, para indexar una interfaz y recuperar el tipo de esa propiedad dada en la interfaz. Es un poco difícil de describir, así que esto es lo que estoy tratando de hacer:
type Props = { propertyName: keyof AppState; options: AppState[propertyName]; };Interfaz ficticia:
export interface AppState { A: string; B: number[]; } Sin embargo, no está funcionando. Supongo que no le gusta la auto referencia, también traté de usar this.propertyName .
Editar:
La respuesta de szaman fue muy útil e hizo exactamente lo que pedí. Simplemente no me di cuenta de que no funcionaría de inmediato como pensaba como un tipo de propiedad de argumento de función. Hice una pregunta incompleta por ignorancia, mi error.
Aquí está el tipo de accesorios actualmente:
type Props<T extends keyof AppState> = { propertyName: T; // options is going to be an array of type of given propertyName values options: AppState[T][]; }La interfaz ficticia de AppState se mantiene igual. Aquí hay un componente funcional ficticio:
const MyComponent: React.FC<Props> = props => {...}El problema ahora es que necesito especificar qué propiedad exacta de AppState se debe escribir el componente funcional durante la declaración de la función. El error es el siguiente:
Generic type 'Props' requires 1 type argument(s).
Mi objetivo es poder usar esta función en otro lugar con cualquier propiedad que tenga AppState. TS detectaría automáticamente el tipo de valor de propiedad y me advertiría si el tipo de options no coincide con el tipo de valor de propiedad dado.
Caso de trabajo:
<MyComponent propertyName="A" options={["foo", "bar"]} />Caso de error:
<MyComponent propertyName="A" options={[0, 1]} /> En el segundo caso de error, mi intención es que TS detecte automáticamente que los valores de la matriz de opciones proporcionadas no son iguales al tipo de nombre de propiedad "A" de AppState. ¿Es posible hacer esto?
Puede lograrlo usando tipos genéricos con restricciones.
type Props<T extends keyof AppState> = { propertyName: T; options: AppState[T]; }; let a: Props<"A"> = { propertyName: "A", options: "foo" } // this is invalid: let aInvalidOptions: Props<"A"> = { propertyName: "A", options: [8, 9] } Aquí estamos usando Props<T> , que es una sintaxis especial para tipos genéricos. También le agregamos una restricción ( type Props<T extends keyof AppState ) para que solo acepte tipos basados en nuestra interfaz AppState .
Luego estamos usando el tipo pasado para determinar el tipo de la propiedad de options . Como beneficio adicional, incluso podemos asegurarnos de que propertyName coincida con nuestro tipo restringido.
Su tipo actual actualmente tiene propertyName y options que son uniones de las posibles claves y valores, respectivamente. Sin embargo, debe crear una unión de nivel superior de cada una de las propiedades y sus respectivas opciones. Esto se puede hacer a través de tipos asignados que nos permiten iterar a través de las claves para crear un nuevo objeto. Luego, podemos aplanar este nuevo objeto creado accediendo a él con keyof T para obtener una unión de las posibles combinaciones del objeto { propertyName, options } .
type Props<T> = { [K in keyof T]: { propertyName: K; options: T[K][] } }[keyof T]; // { propertyName: "hello"; options: string[]; } // | { propertyName: "to"; options: number[]; } // | { propertyName: "you"; options: string[]; } type MyProps = Props<{ hello: string; to: number; you: string; }>; const foo: MyProps = { propertyName: "hello", options: ["asdf"] }; const foo2: MyProps = { propertyName: "to", options: [5, 3], }; const foo3: MyProps = { propertyName: "hello", // @ts-expect-error It fails if you have an invalid option. options: ["asdf", 2] }; const foo4: MyProps = { // @ts-expect-error It fails if you have an invalid name. propertyName: "not-a-valid-name", options: ["hey", 'you'] };