Typescript: El compilador informa incorrectamente la discrepancia de firma de destino de llamada / parámetro cuando se usa el operador de propagación

Creado en 3 ago. 2015  ·  55Comentarios  ·  Fuente: microsoft/TypeScript

El compilador informa incorrectamente una discrepancia de firma de destino de llamada / parámetro cuando se utiliza el operador de propagación. Pegando este código en TypeScript Playground:

function foo(x: number, y: number, z: number) { }
var args = [0, 1, 2];
foo(...args);

produce este error:

Supplied parameters do not match any signature of call target.
Bug Fixed

Comentario más útil

@ jpike88 Sé que tiene
de TS como tú 🕺

Todos 55 comentarios

Y lo mismo ocurre cuando args es de any -type

function foo(x: number, y: number, z: number) { }

function bar(...args) {
    foo(...args); // Supplied parameters do not match any signature of call target.
}

esto es actualmente por diseño. pero deberíamos reconsiderarlo.

@smashdevcode , @tjoskar , estoy buscando algunos usos del mundo real de esta función. Específicamente, ¿espera distribuir matrices o tuplas (o quizás ambas)? Aquí hay un par de ejemplos de juguetes:

//// arrays ////
var a1: number[] = [1,2];
var a2: number[] = [1,2,3];
var a3: number[] = [];
function twoNumbersOrSo(n?: number, m?: number) {
  return (n || -1) * (m || -1);
}
function howManyNumbersLessOne(n?: number, ...ns: number[]) {
    return ns.length;
}

//// tuples ////
var t1: [number, string] = [1, "foo"];
var t2: [number, string, string] = [1, "foo", "bar"];
function veryTraditional(n: number, s: string) {
    for (let i = 0; i < n; i++) {
        console.log(s);
    }
}
function moreInteresting(n: number, s: string, ...rest: string[]) {
    veryTraditional(n, s);
    console.log(rest);
}

Ahora cualquiera de a1,a2,a3 puede aplicarse a las dos primeras funciones, y cualquiera de t1,t2 puede aplicarse a las dos segundas.

Observe que con matrices:

  1. Tienen un solo tipo, por lo que todos los parámetros deben ser del mismo tipo. (Supongo que esto podría ser any .)
  2. La longitud de las matrices no se conoce en tiempo de compilación, por lo que los parámetros deben ser opcionales. Y el argumento de la propagación tiene que ser el último (como hoy).

Con tuplas:

  1. El valor deberá tener una anotación de tipo en algún momento. De lo contrario, se interpretará como una matriz (por ejemplo, (number | string)[] no [number, number, string] ). En el código de juguete, esto borra cualquier ahorro en breve, pero podría estar bien en un proyecto real que ya define muchas interfaces.
  2. La longitud se conoce de antemano, por lo que se puede aplicar una tupla a cualquier tipo de lista de parámetros.

Hola @sandersn ,

Perdón por la respuesta tardía. Extrañé totalmente tu respuesta.
Solo uso matrices con un tipo de datos, por lo que la versión de tupla no es muy interesante para mí.
Sin embargo, creo que la operación de propagación en las llamadas a funciones debería aceptar cualquier objeto iterable. Entonces debería funcionar con eg. map y set , y en estos casos necesitaremos crear una interfaz que funcione con el operador de propagación incluso si los datos contienen múltiples tipos de datos (por ejemplo, new Set (). Add (1) .add ('cadena')). ¿Pero ese es quizás otro boleto?

Ejemplo con Set y la operación de propagación (funciona en Chrome 46)

function foo(...args) {
    console.log(...args);
}
var bar = new Set().add(1).add(2);

foo(...bar); // 1, 2

Sí, es un tema aparte. Typecript ya admite matrices como tipo para parámetros de descanso, que es lo que debería hacerse genérico. Solo estamos discutiendo dónde se podrían usar los argumentos de propagación.

¿Quiere pasar sus matrices / conjuntos homogéneos a funciones con parámetros de descanso o con un número fijo de argumentos? Me gustaría más detalles sobre lo que llamarías.

En primer lugar, he estado jugando con el operador de propagación esta mañana y la mayoría de mis casos de uso funcionan bien en la última versión de mecanografiado [email protected] y en http://www.typescriptlang.org/Playground. Entonces esto ya no es un gran problema.

Sin embargo,
No me gusta la idea de hacer que todos los parámetros sean opcionales solo para poder usar
operador de propagación PERO entiendo el problema; la longitud de las matrices no se conoce en tiempo de compilación, por lo que
es imposible comprobar los parámetros durante la compilación.

Sin embargo, creo que sería bueno que los parámetros no fueran opcionales y que el compilador
solo verifique que "spread-variable" sea del tipo correcto, por ejemplo. número[]

function fun1(x: number, y: number, z: number) {
    return x+y+z;
}

let arr1 = [1, 2, 3];
let arr2 = [1, 2];

fun1(...arr1);
fun1(...arr2); // OK since `arr2` is number[]
fun1(1, 2); // Should cause an error

¿Es eso posible?

El siguiente código funciona en la versión actual de mecanografiado, lo que no funcionaba cuando se abordó este problema.

function fun1(...num) {
    return Math.max(...num);
}

function fun2(a1, ...num) {
    return Math.max(...num);
}

function fun3(a1, ...num) {
    return fun1(...num);
}

let arr = [1, 2, 3];

if (Math.random() < .5) {
    arr.push(1);
}

fun1(...arr);
fun2('first param', ...arr);
fun3('first param', ...arr);

Quizás un ejemplo más realista (que también funciona hoy en día):

const doSomeWork = ({title, genre, runtime}) => { console.log(title, genre, runtime); };

function fun1(...num) {
    num.forEach(doSomeWork);
}

const data = [{
    title: 'title',
    genre: ['action', 'drama'],
    runtime: 100
}];

fun1(...data);

: +1: tiene el mismo problema, con el caso de uso específico del constructor Date :

let dateNumberArray: Array<number> = [2015,11,11];
let myNewDate = new Date(...dateNumberArray);

Para nosotros, utilizamos spreads para permitir a los usuarios configurar los requisitos de argv en una aplicación base sin la necesidad de crear sus propios ayudantes. Por ejemplo:

{
  "yargv": [
    [
      "path",
      {
        "demand": true,
        "describe": "Source",
        "default": ".",
        "alias": "p"
      }
    ]
  ]
}
get appArgs() : { yargv: Array<Array<any>>, chdir: Array<boolean | string> } {
  return require(
    "../args.json"
  )
}

argv() : Promise<{}> {
  return new Promise((resolve) => {
    this.appArgs.yargv.forEach(v => yargs.option(...v))
    return resolve(yargs.usage("$0 [args]").help("h").
      alias("h", "help").argv)
  })
}

Un ejemplo del mundo real usando la función combineLatest de https://github.com/ReactiveX/rxjs donde quiero preservar el this al llamar a projectFn usando una función de flecha y usar parámetros de descanso para propagar los argumentos.

getCombination() {
    return this.firstObservable
      .combineLatest(this.secondObservable, (...args) => this.projectFn(...args)));
  }

Actualmente tengo que hacer

getCombination() {
    return this.firstObservable
      .combineLatest(this.secondObservable, (...args) => this.projectFn.apply(this, args)));
  }

FWIW, otro ejemplo del mundo real está tratando de fusionar en profundidad una matriz de objetos usando fusionar desde lodash:

import { merge } from 'lodash';

...
return merge(...arrayOfObjects);

Aquí hay otro caso de uso del mundo real; estamos tratando de refactorizar el código que se ve así:

return Observable
      .forkJoin(a, b)
      .map(([current, past]) => this.mergeData(current, past));

A lo un poco más elegante:

return Observable
      .forkJoin(a, b)
      .map(data => this.mergeData(...data));

Pero el uso del operador de propagación desencadena el error de discrepancia de firma.

Otro ejemplo

class Parent {
    constructor(a, b, c){

    }
}

class Child extends Parent {
    constructor(d, ...args) {
        super(...args);
    }
}

TS2346: Los parámetros proporcionados no coinciden con ninguna firma del destino de la llamada.

El mismo problema con los métodos de sobrecarga:

listen(port: number, hostname?: string, backlog?: number, listeningListener?: Function): Server;
listen(port: number, hostname?: string, listeningListener?: Function): Server;
listen(port: number, backlog?: number, listeningListener?: Function): Server;
listen(port: number, listeningListener?: Function): Server;
listen(path: string, backlog?: number, listeningListener?: Function): Server;
listen(path: string, listeningListener?: Function): Server;
listen(options: ListenOptions, listeningListener?: Function): Server;
listen(handle: any, backlog?: number, listeningListener?: Function): Server;
listen(handle: any, listeningListener?: Function): Server;

mientras se llama como

myListen(...args) {
    listen(...args);
}

entonces: _ [ts] Los parámetros suministrados no coinciden con ninguna firma del objetivo de la llamada ._

Entonces, por ahora, es imposible hacer tal cosa:

export type DateProp = Date | (string|number)[];

const setDate = (value: DateProp): Date => (
    isDate(value) ? value : new Date(...value)
);

Como está produciendo error:

Los parámetros proporcionados no coinciden con ninguna firma del objetivo de la llamada.

Incluso si el valor contiene los valores correctos de los parámetros del constructor de fecha @mhegazy ? ¿O no obtengo algo?

Incluso si el valor contiene los valores correctos de los parámetros del constructor de fecha @mhegazy ? ¿O no obtengo algo?

Eso es correcto, esto es lo que rastrea este problema.

Me siento obligado a preguntar si puedo ayudar / contribuir de alguna manera. Si es ahora, ¿puede explicar por qué exactamente está causando un error en este caso? ¿Se puede omitir de alguna manera a través de la configuración?

De hecho, tuve este problema cuando cambié el nombre de un archivo .js a .ts . De todos modos, un ejemplo de "no todos los JS válidos son TS válidos".

Actualmente tengo este problema al implementar el ejemplo de plantillas de medios del componente con estilo.

import {css} from 'styled-components';

export const Breakpoints = {
    tablet: 580,
    desktop: 800,
};

export type BreakpointLabels = keyof typeof Breakpoints;

export const media = Object.keys(Breakpoints).reduce((mediaQueries, label: BreakpointLabels) => (
    {
        ...mediaQueries,
        [label]: (...args: any[]) =>
            css`
                <strong i="7">@media</strong> (max-width: ${Breakpoints[label]}px) {
                    ${css(...args)}
                      ^^^^^^^^^^^^ Supplied parameters do not match any signature of call target.
                }
            `
    }
), {});

Mi solución es usar css.call , que al menos funciona con los argumentos de tipo any[] :

import {css} from 'styled-components';

export const Breakpoints = {
    tablet: 580,
    desktop: 800,
};

export type BreakpointLabels = keyof typeof Breakpoints;

export const media = Object.keys(Breakpoints).reduce((mediaQueries, label: BreakpointLabels) => (
    {
        ...mediaQueries,
        [label]: (...args: any[]) =>
            css`
                <strong i="13">@media</strong> (max-width: ${Breakpoints[label]}px) {
                    ${css.call(this, ...args)}
                }
            `
    }
), {});

mismos problemas, mi ejemplo es la función de fusión básica:

merge(target: T, ...sources: T[])

¿Hay alguna solución para silenciar este error al menos por archivo?

En realidad, me gustaría ver las razones por las que esta posibilidad de ES6 se rompe por diseño o cualquier plan cuando podría reconsiderarse. @mhegazy por favor comenta.

Recientemente, hicimos un cambio para permitir la propagación en expresiones de llamada si el objetivo es todo opcional (consulte https://github.com/Microsoft/TypeScript/pull/15849). El cambio funciona al tratar una salida extendida como un conjunto infinito de argumentos opcionales.

Con este cambio, aquí está el estado actual en ejemplos:

declare var args: number[];

function foo(x?: number, y?: number, z?: number) { }
foo(...args);     // OK
foo(2, ...args);  // OK

function bar(...args: number[]) { }
bar(...args);     // OK
bar(2, ...args);  // OK

function baz(x: number, y: number, z: number) { }
baz(...args);     // still not allowed

En el último ejemplo, el compilador no tiene forma de validar que args satisfacen los baz requeridos, ya que la longitud de args no se puede validar estáticamente.

Lo que queda en esta área es permitir que las tuplas con tamaño conocido satisfagan funciones con argumentos requeridos de la misma longitud ... pero esto no es tan simple como puede parecer. p.ej:

function baz(x: number, y: number, z: number) { }
var tuple: [number, number, number] = [1, 2, 3];
baz(...tuple);     // should be allowed

Tengo el mismo problema que @devrelm

Sigo teniendo problemas con esto, ¿qué pasa?

class A {
    constructor(message: string, test?: any) {
        console.log('A constructor called');
    }
}

class B extends A {
    constructor(...spread) {
        super('a', ...spread);
    }
}

Da un error en el patio de juegos mecanografiado

@owlcode esto está en TS 2.4 pero el patio de juegos está en TS 2.3 hasta después de las versiones 2.4.

Esto parece estar solucionado en TS 2.4,

export function log(...args: any[]) {
    console.log(...join(args.map(formatDevTools),' '));
}

Sin embargo, parece haber un nuevo error en TS 2.4:

TS2461: Tipo 'Iterable'no es un tipo de matriz.

Ocurre cuando intentas difundir un iterable ( [...obj] ).

Y, sin embargo, un error diferente (creo) en 2.4.1-insiders.20170615 que aún no he podido averiguar.

Tampoco sé cómo sortear este. Convertir nuestras matrices a any[] no ayudará.


No importa, podemos arreglar la definición de Console ,

interface _Console {
    assert(test?: boolean, message?: string, ...optionalParams: any[]): void;
    clear(): void;
    count(countTitle?: string): void;
    debug(...optionalParams: any[]): void;
    dir(value?: any, ...optionalParams: any[]): void;
    dirxml(value: any): void;
    error(...optionalParams: any[]): void;
    exception(message?: string, ...optionalParams: any[]): void;
    group(groupTitle?: string): void;
    groupCollapsed(groupTitle?: string): void;
    groupEnd(): void;
    info(...optionalParams: any[]): void;
    log(...optionalParams: any[]): void;
    msIsIndependentlyComposed(element: Element): boolean;
    profile(reportName?: string): void;
    profileEnd(): void;
    select(element: Element): void;
    table(...data: any[]): void;
    time(timerName?: string): void;
    timeEnd(timerName?: string): void;
    trace(...optionalParams: any[]): void;
    warn(...optionalParams: any[]): void;
}

Y luego lanza el objeto console :

export function log(...args: any[]) {
    (console as _Console).log(...join(args.map(formatDevTools),' '));
}

Eso tendrá que ser suficiente por ahora.

Abrí un PR para esto en # 18004.

Por ahora, tendré que habilitar "noStrictGenericChecks" en mi tsconfig.

Por ahora, tendré que habilitar "noStrictGenericChecks" en mi tsconfig.

No estoy seguro de ver cómo se relaciona esto con este error ...

No estoy seguro de ver cómo se relaciona esto con este error.

@mhegazy Esta configuración deshabilita todas las firmas de funciones, por lo que puedo pasar argumentos usando el operador de propagación sin hacer coincidir la cantidad de argumentos (al menos no estáticamente)

eso no es lo que hace --noStrictGenericChecks . Consulte https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#stricter -checking-for-generic-functions

Acabo de encontrarme con esto.

Si bien puedo entender que es difícil, al menos los argumentos "en exceso" deberían poder identificar.

@sandersn desde una perspectiva del mundo real, estábamos refactorizando una API para aceptar un solo argumento o una matriz, en lugar de usar un argumento de descanso. Por lo tanto, las situaciones en las que pasamos algo como foo(value, ...otherValues) no se identificaron como errores. Específicamente, esto parece realmente peligroso :

declare const foo: (value: string) => string;

foo('bar', 'qat'); // Expected 1 arguments, but got 2.

foo('bar', ...['qat']); // No error

@kitsonk, ¿puedes abrir un error separado para eso? Sería más fácil de considerar de forma aislada, y probablemente sea una pequeña modificación de las reglas existentes, en lugar de un cambio complejo.

Incluso si verifico la longitud, sigo recibiendo este error:

function myFunc(...args: any[]) {
  if(args.length > 0) {
    otherFunc(...args)
  }
}

Editar:

Para aclarar la confusión, me redirigieron desde aquí , que dice:

Se esperaban 2 argumentos, pero obtuvo un mínimo de 0

Ese problema se consideró una duplicación de este problema.

En mi caso, pude corregir mi error (más como un truco que una solución) al permitir que no se pasara nada al método agregando function otherFunc() como uno de los inicializadores así:

function otherFunc()
function otherFunc(arg1: string)
function otherFunc(arg1: string, arg2: number)
function otherFunc(...args: any[]) {
  // Do stuff
}

Esta solución se rompe en 2.7

¿Cómo sigue siendo esto un problema? Los operadores de propagación son una forma perfectamente compatible de trabajar en JS, por lo que TS debería contabilizarlo correctamente.

@ jpike88 Sé que tiene
de TS como tú 🕺

Otro buen caso de prueba (en realidad una regresión de TS 2.7) es este:

class NonEmptyArray<T> extends Array<T> {
        0: T;
}

function c(firstArg: string, ... plainValues: string[]): string;
function c(): undefined;
function c(...values: string[]): string | undefined {
        if (!values.length) {
                return undefined;
        }
        return "";
}


function d(): NonEmptyArray<string> {
        return [""];
}

function y(): string | undefined {
        return c(...d());
}

Produce

test.ts (20,9): error TS2557: Se esperaba al menos 0 argumentos, pero obtuvo 0 o más.

Otro problema que encontré con respecto al operador de propagación:

const get = (id?: string = '1231254', bar?: Bar, baz?: Baz) => {...}
const foo: [undefined, Bar, Baz] = [undefined, bar, baz]

get(...foo) // [ts] Argument of type 'Bar | Baz' is not assignable to parameter  
of type 'string'.
Type 'Baz' is not assignable to type 'string'

Por supuesto, en ES6 no tengo ningún problema para extender la matriz con indefinidos incluidos como argumentos y pasar correctamente los undefined pero parece que TS simplemente ignora los valores undefined cuando los extiende.

Otro ejemplo del mundo real, en el que el manejo correcto del operador de propagación en la llamada de función ayudará mucho:
Tengo funciones generadas por NSwagStudio - generador de API para C # WebApi, que tienen los mismos parámetros (los parámetros GET están definidos en la estructura)

La función generada se parece a lo siguiente:

export interface ITableApiClient {
    getTableInfo(objnam: string | null, objsch: string | null | undefined, dbnam: string | null, conid: number | undefined): Promise<FileResponse | null>;
    otherFunction(objnam: string | null, objsch: string | null | undefined, dbnam: string | null, conid: number | undefined): Promise<string | null>;
}

Quiero llamarlo con sintaxis

   get tableIdentification() {
       return [this.name, this.schema, this.databaseName, this.serverConnectionId];
   }
...
   return apiClient.getTableInfo(...this.tableIdentification);

   // this doesn't help, still compile-time error
   // return apiClient.getTableInfo(...(this.tableIdentification as any));

porque hay más funciones con exactamente los mismos parámetros (porque se generan a partir de la misma clase de parámetros definida en el backend de C #). Ahora tengo que copiar el cuerpo de la propiedad tableIdentification n veces en cada uso

@smashdevcode Para mí, la solución fue agregar @ ts-ignore

function foo(x: number, y: number, z: number) { }
var args = [0, 1, 2];
// @ts-ignore
foo(...args);

ejemplo aquí: https://stackblitz.com/edit/typescript-ecymei?embed=1&file=index.ts

@ darekf77 , o si dices que args es una tupla:

function foo(x: number, y: number, z: number) { }
const args: [number, number, number] = [0, 1, 2];
foo(...args);

ts-patio de recreo

@ darekf77 , o si dices que args es una tupla:

function foo(x: number, y: number, z: number) { }
const args: [number, number, number] = [0, 1, 2];
foo(...args);

Esto me funciona cuando compilo mecanografiado en la línea de comandos, pero no cuando Visual Studio Code valida el mecanografiado mientras escribo. No estoy seguro de cuál es la desconexión aquí.

Veo que ha pasado más de un año desde que jayphelps mencionó que esto se solucionaría en una próxima versión, pero este problema aún ocurre. ¿Hay alguna actualización sobre esto? Sé que podría usar @ ts-ignore, sin embargo, esto elimina TODOS los mensajes mecanografiados para la función, por lo que no es realmente una solución adecuada.

@TidyIQ como lo menciona tjoskar, encasilla tu matriz de dispersión como una tupla.

La matriz no es de longitud fija, por lo que no funcionará.

Un encasillamiento funcionará en lo que respecta al compilador, incluso si es inexacto. Estoy de acuerdo en que no es la mejor solución.

(Esta pregunta probablemente debería trasladarse al desbordamiento de pila (o similar))

@TidyIQ , si la matriz no tiene una longitud fija, el compilador no puede decir si la matriz es adecuada o no.

function foo(x: number, y: number, z: number) { }
const args = arrayOfSomeLength;
foo(...args); // Error: The compiler do not know if there is 3 or 2 or 1 or 50 elements in the array. 

Entonces, si la matriz es de longitud dinámica, los argumentos también deberían ser los siguientes:

function foo(...args: number[]) { }
const args = arrayOfSomeLength;
foo(...args);

Patio de recreo

Desafortunadamente, eso tampoco funcionará ya que algunos de mis argumentos son de longitud fija.

Quizás si publico el código, es posible que vea el problema.

interface IF_Object {
  [key: string]: object;
}
//  VALUE SHOULD BE REQUIRED BUT MADE OPTIONAL TO BYPASS TYPESCRIPT ERROR
interface IF_SetKV {
  (key: string, value?: any): Function;
}
//  VALUE SHOULD BE REQUIRED BUT MADE OPTIONAL TO BYPASS TYPESCRIPT ERROR
interface IF_CreateState {
  (key: string, value?: any, ...more: string[]): Function;
}

const setKV: IF_SetKV = (key, value) => (object: IF_Object = {}) => ({
  ...object,
  [key]: value
});

const createState: IF_CreateState = (key, value, ...more) => (
  object: IF_Object = {}
) =>
  more.length === 0
    ? setKV(key, value)(object)
    : setKV(key, createState(value, ...more)(object[key]))(object);

// TYPESCRIPT ERROR OCCURS HERE. CAN ONLY BE REMOVED WITH TS<strong i="7">@IGNORE</strong>
const newState = createState(...stateList, action.payload.value)(reduced);

@TidyIQ , no estoy seguro de seguirlo. ¿Qué sucede si stateList es una matriz vacía? En ese caso, ¿ action.payload.value se pasará como key ?

¿No debería funcionar esto:

const createState = (...args: string[]) => (object: IF_Object = {}) => {
  const [key, value, ...rest] = args;
  if (rest.length === 0) {
    setKV(key, value)(object)
  } else {
    setKV(key, createState(value, ...rest)(object[key]))(object);
  }
}

Transmitir para distribuir el valor como ParameterType de la función a la que está pasando argumentos.

const add = (a: number, b: number) => a + b

const values = {
  a: 1,
  b: 2,
}

type AddParams = Parameters<typeof add>

add(...(values) as AddParams)

@ mateja176 Esto también parece funcionar y podría adaptarse mejor a algunos casos de uso.

add(...(values as [number,number]))

o

add(...(values as [any,any]))

Utilizo un tipo de ayuda para esto para manejar matrices arbitrarias sin tener que escribirlas explícitamente:

type NonEmptyArray<T extends any[]> = T extends (infer U)[]
  ? [U, ...U[]]
  : never

Se puede usar así:

add(...values as NonEmptyArray<typeof values>)


Explicación detallada para principiantes

La siguiente disección del tipo NonEmptyArray explica cómo funciona en detalle:

# | Parte | Explicación
- | - | -
(1) | type NonEmptyArray | El nombre del tipo de ayudante
(2) | <T | El tipo de ayuda toma un parámetro de tipo genérico T .
(3) | extends any[]> | Para ser aceptado por el verificador de tipo, ese parámetro de tipo T debe ser un tipo de matriz.
(4) | T extends (infer U)[] ? | Nuestro tipo de ayuda es un tipo condicional que comprueba si T realidad es un tipo de matriz.
Hemos declarado T como un tipo de matriz en (3), por lo que esta condición siempre pasa, pero usar el condicional nos permite dejar que TypeScript infer el tipo que la matriz T está hecho, y llamamos a ese tipo U .
(5) | [U, ...U[]] | Ahora podemos ensamblar el tipo resultante: una matriz donde la primera entrada es de tipo U y las entradas restantes (0 o más) también son de tipo U .
Debido a esta notación de tupla específica, TypeScript es consciente de que hay al menos un elemento.
(6) | : never | Esto solo es necesario para completar sintácticamente el condicional. Recuerde: el condicional es solo un truco para extraer el tipo U , y siempre pasa. Por lo tanto, podemos ignorar con seguridad la rama "else" obteniendo never .


Ahora si hacemos esto ...

ts const values = [1,2,3] add(...values as NonEmptyArray<typeof values>)

... ocurrirá lo siguiente:

  • typeof values es el tipo que TypeScript infirió para la matriz values , que es una matriz de números: number[] .
  • Eso significa que pasamos number[] como T . (2/3)
  • T es de hecho un tipo de matriz, por lo que podemos inferir U de ella, que es number . (4)
  • Ahora que sabemos que U es un number , obtenemos el tipo [number, ...number[]] . (5)

@tjoskar cambia tu código a

function foo(x: number, y: number, z: number, f: number) { }
const args: [number, number, number] = [0, 1, 2];
foo(...args, 3);

( patio de recreo )
Y el error ha vuelto.

Sorprendentemente, si tuviera que cambiar la última línea a foo(3, ...args); , no habrá ningún error.

Siento que esto todavía no funciona. Aqui esta mi ejemplo

onSetValue={(...args: Parameters<typeof props.onSetValue>) => {
    setLanguage(null);
    props.onSetValue(...args); // Expected 2 arguments, but got 0 or more.
  }}

Realmente no debería importar cuál es el tipo de props.onSetValue , porque simplemente tomo el tipo de parámetros y lo paso a la función de la que obtuve el tipo y todavía da el error Expected 2 arguments, but got 0 or more. .

Enlace de patio de recreo

Aquí hay una forma reducida del ejemplo de @ Haaxor1689 :
Enlace de patio de recreo

Todavía no puedo hacerlo funcionar

esta es mi solución temporal

class Board {
  private events: Events

  public on(...args: Parameters<this['events']['on']>) {
    this.events.on.call(this.events, ...args)
  }
}
¿Fue útil esta página
0 / 5 - 0 calificaciones