Búsqueda de sitios web

Typescript: convertir una unión de array de ObjectId o string a un array de string


Tengo un arreglo foo del tipo:

foo: ObjectId[] | string[];

Necesito asignarlo a un arreglo de cadenas bar de la siguiente manera:

let bar : string[] = foo.map( (e) => e.toString())

Esto debería ser correcto ya que tanto los tipos ObjectID como string tienen definido el método toString(). Sin embargo, el código anterior no se compila debido al siguiente error:

This expression is not callable.
  Each member of the union type '(<U>(callbackfn: (value: ObjectId, index: number, array: ObjectId[]) => U, thisArg?: any) => U[]) | (<U>(callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => U[])' has signatures, but none of those signatures are compatible with each other.

Actualmente estoy utilizando la siguiente solución temporal:

let bar : string[] = (foo as Array<string|ObjectID>).map( (e) => e.toString())

¿Hay alguna forma mejor de convertir un array de tipo mixto a cadena?

Respuesta #1

Permitiendo foo.map()

Funcionará si defines foo con una firma que diga "es un arreglo de cadenas y ObjectIds, y también es un arreglo de todos los ObjectIds o todas las cadenas". Esto parece tonto porque la primera parte está implícita en la segunda parte, pero TypeScript no funciona de esa manera.

foo: (ObjectId | string)[] & (ObjectId[] | string[]);

Esto es mejor que hacer un casting as (ObjectId | string)[] porque no perdemos la información de que el arreglo debe ser de un solo tipo. Pero incluir (ObjectId | string)[] como parte del tipo significa que está bien mapearlo.

Puedes convertir esto en un tipo utilitario:

type ArrayOfEither<A, B> = (A | B)[] & (A[] | B[]);

Mapeando foo a través de una función

Si no puedes cambiar el tipo de foo, entonces puedes hacer tu mapeo en una función separada que tome foo como argumento.

Esto funciona porque la firma original ObjectId[] | string[] es muy específica, pero se puede asignar a tipos más amplios como ArrayOfEither<ObjectId[], string[]> o simplemente Stringable[].

interface Stringable {
    toString(): string;
}

const myFunction = ( array: Stringable[] ): string[] => {
    return array.map(e => e.toString());
}

declare const foo: ObjectId[] | string[];

myFunction(foo); // no errors

Enlace del parque

Artículos relacionados