Typescript: O compilador relata incorretamente a incompatibilidade de assinatura de parâmetro / destino de chamada ao usar o operador de propagação

Criado em 3 ago. 2015  ·  55Comentários  ·  Fonte: microsoft/TypeScript

O compilador relata incorretamente uma incompatibilidade de assinatura de parâmetro / destino de chamada ao usar o operador de propagação. Colando este código no Playground TypeScript:

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

produz este erro:

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

Comentários muito úteis

@ jpike88 Sei que você tem boas
de TS como você 🕺

Todos 55 comentários

E o mesmo é para quando args é do tipo any

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

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

isso é atualmente por design. mas devemos reconsiderar isso.

@smashdevcode , @tjoskar , estou procurando alguns usos reais desse recurso. Especificamente, você espera espalhar arrays ou tuplas (ou talvez ambos)? Aqui estão alguns exemplos de brinquedos:

//// 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);
}

Agora qualquer um de a1,a2,a3 pode ser aplicado às duas primeiras funções e qualquer um de t1,t2 pode ser aplicado às duas segundas.

Observe que com matrizes:

  1. Ter um único tipo, portanto, todos os parâmetros devem ser do mesmo tipo. (Acho que pode ser any .)
  2. O comprimento dos arrays não é conhecido no momento da compilação, portanto, os parâmetros devem ser opcionais. E o argumento de propagação tem que ser o último (como hoje).

Com tuplas:

  1. O valor deverá ter uma anotação de tipo em algum ponto. Caso contrário, será interpretado como um array (por exemplo, (number | string)[] not [number, number, string] ). No código de brinquedo, isso elimina qualquer economia em brevidade, mas pode ser OK em um projeto real que já define muitas interfaces.
  2. O comprimento é conhecido com antecedência, portanto, uma tupla pode ser aplicada a qualquer tipo de lista de parâmetros.

Olá @sandersn ,

Desculpe pela resposta tardia. Eu perdi totalmente sua resposta.
Eu só uso arrays com um tipo de dados, então a versão da tupla não é muito interessante para mim.
No entanto, acho que a operação de propagação em chamadas de função deve aceitar qualquer objeto iterável. Portanto, deve funcionar com, por exemplo. map e set e, nesses casos, precisaremos criar uma interface que funcione com o operador de propagação, mesmo se os dados contiverem vários tipos de dados (por exemplo, new Set (). Add (1) .add ('string')). Mas isso talvez seja outro ingresso?

Exemplo com Set e a operação spread (funciona no Chrome 46)

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

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

Sim, é um problema separado. O typescript já suporta arrays como o tipo para os parâmetros de resto, que é o que precisa ser tornado genérico. Estamos apenas discutindo onde os argumentos espalhados podem ser usados.

Você quer passar seus arrays / conjuntos homogêneos para funções com parâmetros de descanso ou aqueles com um número fixo de argumentos? Eu gostaria de mais detalhes sobre a coisa para a qual você ligaria.

Em primeiro lugar, estou brincando com o operador spread esta manhã e a maioria dos meus casos de uso funciona bem na versão mais recente do typescript [email protected] e em http://www.typescriptlang.org/Playground. Portanto, isso não é mais um grande problema.

Contudo,
Não gosto da ideia de tornar todos os parâmetros opcionais apenas para poder usar
spread operador MAS eu entendo o problema; o comprimento dos arrays não é conhecido em tempo de compilação, então
é impossível verificar os parâmetros em tempo de compilação.

No entanto, acho que seria bom se os parâmetros não precisassem ser opcionais e que o compilador
apenas verifique se a "variável de propagação" é do tipo correto, por exemplo. 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

Isso é possível?

O código a seguir funciona na versão atual do typescript, o que não funcionava quando esse problema foi resolvido.

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);

Talvez um exemplo mais realista (que também funciona hoje em dia):

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: Tendo o mesmo problema, com o caso de uso específico do construtor Date :

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

Para nós, usamos spreads para permitir que os usuários configurem requisitos argv em um aplicativo base sem a necessidade de construir seus próprios ajudantes. Por exemplo:

{
  "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)
  })
}

Um exemplo do mundo real usando a função combineLatest de https://github.com/ReactiveX/rxjs onde eu quero preservar o this ao chamar projectFn usando uma função de seta e usar os parâmetros de descanso para propagar os argumentos.

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

Atualmente tenho que fazer

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

FWIW, outro exemplo do mundo real está tentando mesclar profundamente uma matriz de objetos usando mesclagem de lodash:

import { merge } from 'lodash';

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

Aqui está outro caso de uso do mundo real; estamos tentando refatorar um código semelhante a este:

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

Para o um pouco mais elegante:

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

Mas o uso do operador de propagação aciona o erro de incompatibilidade de assinatura.

Outro exemplo

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

    }
}

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

TS2346: Os parâmetros fornecidos não correspondem a nenhuma assinatura do destino da chamada.

Mesmo problema com 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;

enquanto chamado de

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

então: _ [ts] Os parâmetros fornecidos não correspondem a nenhuma assinatura do destino da chamada._

Então, por enquanto, é impossível fazer isso:

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

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

Como está produzindo erro:

Os parâmetros fornecidos não correspondem a nenhuma assinatura do destino da chamada.

Mesmo se o valor contiver valores de parâmetros de construtor de data corretos

Mesmo se o valor contiver valores de parâmetros de construtor de data corretos

Correto, é isso que esse problema está rastreando.

Sinto-me na obrigação de perguntar se posso ajudar / contribuir de alguma forma. Se agora, você pode explicar por que exatamente está causando um erro neste caso? Ele pode ser ignorado de alguma forma na configuração?

Na verdade, fui atingido com esse problema quando renomeei um arquivo .js para .ts . De qualquer forma, um exemplo de "nem todo JS válido é TS válido".

No momento, estou tendo esse problema ao implementar o exemplo de modelos de mídia de componentes com 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.
                }
            `
    }
), {});

Minha solução alternativa é usar css.call , que funciona pelo menos com os argumentos do 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)}
                }
            `
    }
), {});

mesmos problemas, meu exemplo é a função básica de fusão:

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

existe alguma solução alternativa para silenciar esse erro pelo menos por arquivo?

Na verdade, eu gostaria de ver as razões pelas quais essa possibilidade ES6 foi quebrada por design ou quaisquer planos quando ela poderia ser reconsiderada. @mhegazy, por favor, comente.

Recentemente, fizemos uma alteração para permitir a disseminação em expressões de chamada se o destino for opcional (consulte https://github.com/Microsoft/TypeScript/pull/15849). A mudança funciona tratando uma saída de propagação como um conjunto infinito de argumentos opcionais.

Com essa mudança, aqui está o estado atual em exemplos:

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

No último exemplo, o compilador não tem como validar que args satisfaça o baz exigido, uma vez que o comprimento de args não pode ser validado estaticamente.

O que resta nesta área é permitir que tuplas com tamanho conhecido satisfaçam funções com argumentos necessários do mesmo comprimento ... mas isso não é tão simples quanto pode parecer. por exemplo:

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

Eu tenho o mesmo problema de @devrelm

Ainda estou tendo problemas com isso, o que há de errado?

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

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

Ele dá um erro no playground de texto digitado

@owlcode está no TS 2.4, mas o playground está no TS 2.3 até depois das versões 2.4.

Isso parece estar corrigido no TS 2.4,

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

No entanto, parece haver um novo bug no TS 2.4:

TS2461: Digite 'Iterável'não é um tipo de array.

Acontece quando você tenta espalhar um iterável ( [...obj] ).

E ainda um bug diferente (eu acho) em 2.4.1-insiders.20170615 que eu não fui capaz de descobrir ainda.

Eu também não sei como contornar este. Transmitir nossos arrays para any[] não ajudará.


Esqueça, podemos corrigir a definição 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;
}

E então lance o objeto console :

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

Isso terá que servir por enquanto.

Abri um PR para isso no # 18004.

Por enquanto, terei que habilitar "noStrictGenericChecks" em meu tsconfig.

Por enquanto, terei que habilitar "noStrictGenericChecks" em meu tsconfig.

Não tenho certeza se vejo como isso está relacionado a este bug ...

Não tenho certeza se vejo como isso está relacionado a esse bug.

@mhegazy Esta configuração desativa todas as assinaturas de função, então posso passar argumentos usando o operador de propagação sem corresponder à quantidade de argumentos (pelo menos não estaticamente)

não é isso que --noStrictGenericChecks fazem. Consulte https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#stricter -checking-for-generic-functions

Eu acabei de encontrar isso.

Embora eu possa entender que seja difícil, pelo menos os argumentos "excessivos" devem ser capazes de identificar.

@sandersn de uma perspectiva do mundo real, estávamos refatorando uma API para aceitar um único argumento ou um array, em vez de usar um argumento rest. Portanto, as situações em que passamos algo como foo(value, ...otherValues) não foram identificadas como erros. Especificamente, isso parece muito perigoso :

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

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

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

@kitsonk você pode abrir um bug separado para isso? Seria mais fácil considerar isoladamente e provavelmente seria um pequeno ajuste nas regras existentes, em vez de uma mudança complexa.

Mesmo se eu verificar o comprimento, ainda recebo este erro:

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

Editar:

Para esclarecer a confusão, fui redirecionado daqui , que afirma:

Esperava-se 2 argumentos, mas obteve um mínimo de 0

Esse problema foi considerado uma duplicata deste problema.

No meu caso, fui capaz de corrigir meu erro (mais como um hack do que uma correção), permitindo que nada fosse passado para o método, adicionando function otherFunc() como um dos inicializadores assim:

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

Esta solução alternativa é interrompida em 2.7

Como isso ainda é um problema? Operadores de propagação são uma maneira perfeitamente compatível de trabalhar em JS, então o TS deve levar isso em consideração de maneira adequada.

@ jpike88 Sei que você tem boas
de TS como você 🕺

Outro bom caso de teste (na verdade, uma regressão de TS 2.7) é 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());
}

Produz

test.ts (20,9): erro TS2557: Esperado pelo menos 0 argumentos, mas obteve 0 ou mais.

Outro problema que encontrei em relação ao operador de propagação:

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'

Claro, no ES6 eu não tenho nenhum problema em espalhar array com undefined incluídos como argumentos e passar corretamente undefined mas parece que o TS simplesmente ignora undefined valores quando ele os espalha.

Outro exemplo do mundo real, no qual o manuseio correto do operador de propagação na chamada de função vai ajudar muito:
Tenho funções geradas pelo NSwagStudio - gerador de API para C # WebApi, que possuem os mesmos parâmetros (os parâmetros GET são definidos na estrutura)

A função gerada tem a seguinte aparência:

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>;
}

Eu quero chamá-lo com sintaxe

   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 existem mais funções com exatamente os mesmos parâmetros (porque são gerados a partir da mesma classe de parâmetros definida no backend C #). Agora tenho que copiar o corpo da propriedade tableIdentification n vezes em cada uso

@smashdevcode Para mim, a solução foi adicionar @ ts-ignore

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

exemplo aqui: https://stackblitz.com/edit/typescript-ecymei?embed=1&file=index.ts

@ darekf77 , ou se você disser que args é uma tupla:

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

ts-playground

@ darekf77 , ou se você disser que args é uma tupla:

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

Isso funciona para mim quando compilo o texto digitado na linha de comando, mas não quando o Visual Studio Code valida o texto digitado enquanto estou digitando. Não tenho certeza de qual é a desconexão aqui.

Vejo que já se passou mais de um ano desde que jayphelps mencionou que isso seria corrigido em uma versão futura, mas esse problema ainda ocorre. Existe alguma atualização sobre isso? Eu sei que poderia usar @ ts-ignore, no entanto, isso remove TODAS as mensagens digitadas para a função, portanto, não é realmente uma solução apropriada.

@TidyIQ conforme mencionado por tjoskar, faça a projeção de sua matriz de propagação como uma tupla.

A matriz não tem comprimento fixo, então isso não funcionará.

Um typecast funcionará no que diz respeito ao compilador, mesmo que seja impreciso. Concordo que não é a melhor solução.

(Esta questão provavelmente deve ser movida para estouro de pilha (ou semelhante))

@TidyIQ , se o array não tem um comprimento fixo, o compilador não pode dizer se o array é adequado ou não.

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. 

Portanto, se a matriz tiver comprimento dinâmico, os argumentos também devem ser assim:

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

Parque infantil

Infelizmente, isso também não funcionará, pois alguns dos meus argumentos têm comprimento fixo.

Talvez se eu apenas postar o código, você verá o 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 , não tenho certeza se entendi. O que acontece se stateList for um array vazio? Nesse caso, action.payload.value será passado como key ?

Isso não deveria funcionar:

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);
  }
}

Converta para espalhar o valor como ParameterType da função para a qual você está passando 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 Isso também parece funcionar e pode se adequar melhor a alguns casos de uso.

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

ou

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

Eu uso um tipo auxiliar para lidar com matrizes arbitrárias sem ter que digitá-las explicitamente:

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

Ele pode ser usado assim:

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


Explicação detalhada para iniciantes

A seguinte dissecação do tipo NonEmptyArray explica como funciona em detalhes:

# | Parte | Explicação
- | - | -
(1) | type NonEmptyArray | O nome do tipo auxiliar
(2) | <T | O tipo auxiliar recebe um parâmetro de tipo genérico T .
(3) | extends any[]> | Para ser aceito pelo verificador de tipo, o parâmetro de tipo T deve ser algum tipo de array.
(4) | T extends (infer U)[] ? | Nosso tipo auxiliar é um tipo condicional que verifica se T é realmente um tipo de array.
Declaramos T como um tipo de array em (3), então esta condição sempre passa, mas usar a condicional nos permite deixar TypeScript infer o tipo que o array T é feito, e chamamos esse tipo de U .
(5) | [U, ...U[]] | Agora podemos montar o tipo resultante: um array onde a primeira entrada é do tipo U e as entradas restantes (0 ou mais) também são do tipo U .
Por causa dessa notação de tupla específica, o TypeScript está ciente de que há pelo menos um item.
(6) | : never | Isso é necessário apenas para completar sintaticamente a condicional. Lembre-se: a condicional é apenas um truque para extrair o tipo U , e sempre passa. Portanto, podemos ignorar com segurança o branch "else" gerando never .


Agora, se fizermos isso ...

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

... acontecerá o seguinte:

  • typeof values é o tipo que o TypeScript inferiu para o array values , que é um array de números: number[] .
  • Isso significa que passamos number[] como T . (2/3)
  • T é de fato um tipo de array, portanto, podemos inferir U dele, que é number . (4)
  • Agora que sabemos que U é um number , obtemos o tipo [number, ...number[]] . (5)

@tjoskar mude seu código para

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

( playground )
E o erro voltou.

Surpreendentemente, se você alterar a última linha para foo(3, ...args); - não haverá erro.

Eu sinto que isso ainda não está funcionando. Aqui está meu exemplo

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

Não deveria realmente importar qual é o tipo de props.onSetValue , porque eu apenas pego o tipo de parâmetro e o passo para a função de onde obtive o tipo e ainda dá o erro Expected 2 arguments, but got 0 or more. .

Link do parque

Aqui está uma forma reduzida do exemplo de @ Haaxor1689 :
Link do parque

Eu ainda não consigo fazer funcionar

esta é minha solução temporária

class Board {
  private events: Events

  public on(...args: Parameters<this['events']['on']>) {
    this.events.on.call(this.events, ...args)
  }
}
Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

kyasbal-1994 picture kyasbal-1994  ·  3Comentários

fwanicka picture fwanicka  ·  3Comentários

uber5001 picture uber5001  ·  3Comentários

weswigham picture weswigham  ·  3Comentários

manekinekko picture manekinekko  ·  3Comentários