Mi enfoque actual de "trabajo" es este:
const generateMainOrientations = <T extends readonly string[]>( mainOrientationsNames: T ): { [Index in keyof T]: Orientation } => { const temp: Orientation[] = mainOrientationsNames.map( mainOrientationName => ({ name: mainOrientationName, getYear(date) { return date.getFullYear() }, getRecordContent: getMainOrientationRecordContent }) ) return temp as unknown as { [Index in keyof T]: Orientation } } const mainOrientations = generateMainOrientations([ "One", "Two", "Three" ] as const) Sin embargo, tengo que usar as unknown as { [Index in keyof T]: Orientation } , que no es ideal, de lo contrario (incluso eliminando la afirmación de tipo de la variable temp ) arrojará
Type '{ name: string; getYear(date: any): any; getRecordContent: (values: number[]) => string[]; }[]' is not assignable to type '{ [Index in keyof T]: Orientation; }'.ts(2322) Aún así, { name: string; getYear(date: any): any; getRecordContent: (values: number[]) => string[]; } es la definición de Orientation
Esto muestra que cualquier información de longitud se pierde después de usar el mapa.
¿Hay una forma más orgánica de lograr esto, preferiblemente sin tener que usar aserciones de tipo, o al menos sin tener que usar as unknown . El objetivo sería hacer de mainOrientations una tupla de Orientation de la misma longitud que el argumento pasado para generateMainOrientations , así que [Orientation, Orientation, Orientation] en este caso, (no Orientation[] ).
Necesitas sobrecargar tu función:
interface Orientation { name: string, getYear(date: Date): number, getRecordContent(values: number[]): string[] } declare function getMainOrientationRecordContent(values: number[]): string[] function generateMainOrientations<T extends string, Tuple extends T[]>( mainOrientationsNames: [...Tuple] ): { [Index in keyof Tuple]: Orientation } function generateMainOrientations( mainOrientationsNames: string[] ) { return mainOrientationsNames.map( mainOrientationName => ({ name: mainOrientationName, getYear: (date: Date) => date.getFullYear(), getRecordContent: getMainOrientationRecordContent }) ) } // [Orientation, Orientation, Orientation] const mainOrientations = generateMainOrientations([ "One", "Two", "Three" ]) Tenga en cuenta que una vez que usó Array.prototype.map , TypeScript no conserva la longitud del resultado. Aquí puedes encontrar por qué.
por lo tanto, solo tiene dos opciones: sobrecarga y aserción de tipo.
Puede hacerlo aún mejor si hace que la propiedad del name esté parametrizada:
interface Orientation<Name extends string> { name: Name, getYear(date: Date): number, getRecordContent(values: number[]): string[] } declare function getMainOrientationRecordContent(values: number[]): string[] function generateMainOrientations<T extends string, Tuple extends T[]>( mainOrientationsNames: [...Tuple] ): { [Index in keyof Tuple]: Orientation<Tuple[Index] & string> } function generateMainOrientations( mainOrientationsNames: string[] ) { return mainOrientationsNames.map<Orientation<string>>( name => ({ name, getYear: (date) => date.getFullYear(), getRecordContent: getMainOrientationRecordContent }) ) } // [Orientation<"One">, Orientation<"Two">, Orientation<"Three">] const mainOrientations = generateMainOrientations([ "One", "Two", "Three" ])Puedes usar temp as any
const generateMainOrientations = <T extends readonly string[]>( mainOrientationsNames: T ): { [Index in keyof T]: Orientation } => { const temp = mainOrientationsNames.map((mainOrientationName) => ({ name: mainOrientationName, getYear(date: Date) { return date.getFullYear(); }, getRecordContent: getMainOrientationRecordContent })); return temp as any; };