Typescript: Le compilateur signale de manière incorrecte une incompatibilité de signature de paramètre / cible d'appel lors de l'utilisation de l'opérateur de propagation

Créé le 3 août 2015  ·  55Commentaires  ·  Source: microsoft/TypeScript

Le compilateur signale de manière incorrecte une incompatibilité de signature de paramètre / cible d'appel lors de l'utilisation de l'opérateur de propagation. Coller ce code dans le TypeScript Playground:

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

produit cette erreur:

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

Commentaire le plus utile

@ jpike88 Je sais que vous voulez bien dire, mais vous ne réaliserez peut-être pas que des déclarations comme celles-ci sont contre-productives. Le problème est sur leur TODO pour les jalons 2.7 ou 2.8 il ressemble. Cela peut sembler une chose évidente à corriger, mais lorsque vous avez des milliers de choses évidentes à corriger, vous ne pouvez pas les réparer toutes en même temps et continuer à améliorer d'autres choses que l'on attend d'eux. La meilleure façon d'exprimer votre vote est de donner une réaction au post original en haut. C'est un logiciel libre après tout et ils ne nous doivent rien. Cela dit, c'est juste mon avis, un autre utilisateur
de TS comme toi 🕺

Tous les 55 commentaires

Et il en va de même lorsque args est de type any

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

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

c'est actuellement par conception. mais nous devons le reconsidérer.

@smashdevcode , @tjoskar , je recherche des utilisations concrètes de cette fonctionnalité. Plus précisément, prévoyez-vous de diffuser des tableaux ou des tuples (ou peut-être les deux)? Voici quelques exemples de jouets:

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

Maintenant, n'importe lequel des a1,a2,a3 peut être appliqué aux deux premières fonctions, et n'importe lequel des t1,t2 peut être appliqué aux deux secondes.

Notez qu'avec les tableaux:

  1. Avoir un seul type, les paramètres doivent donc tous être du même type. (Je suppose que cela pourrait être any .)
  2. La longueur des tableaux n'est pas connue au moment de la compilation, les paramètres doivent donc être facultatifs. Et l'argument de la propagation doit être le dernier (comme aujourd'hui).

Avec des tuples:

  1. La valeur devra avoir une annotation de type à un moment donné. Sinon, il sera interprété comme un tableau (par exemple (number | string)[] non [number, number, string] ). Dans le code jouet, cela efface toute économie de brièveté, mais cela peut être acceptable dans un projet réel qui définit déjà de nombreuses interfaces.
  2. La longueur est connue à l'avance, donc un tuple peut être appliqué à n'importe quel type de liste de paramètres.

Salut @sandersn ,

Désolé pour la réponse tardive. J'ai totalement manqué votre réponse.
Je n'utilise que des tableaux avec un seul type de données, donc la version tuple n'est pas très intéressante pour moi.
Cependant, je pense que l'opération de propagation dans les appels de fonction devrait accepter n'importe quel objet itérable. Donc, cela devrait fonctionner avec par exemple. map et set , et dans ces cas, nous devrons créer une interface qui fonctionne avec l'opérateur de propagation même si les données contiennent plusieurs types de données (par exemple. New Set (). Add (1) .add ('chaîne')). Mais c'est peut-être un autre ticket?

Exemple avec Set et l'opération de propagation (fonctionne dans Chrome 46)

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

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

Ouais, c'est un problème distinct. Typescript prend déjà en charge les tableaux en tant que type pour les paramètres de repos, ce qui devrait être rendu générique. Nous discutons simplement de l'endroit où les arguments de propagation pourraient être utilisés.

Voulez-vous passer vos tableaux / ensembles homogènes à des fonctions avec des paramètres de repos ou à des fonctions avec un nombre fixe d'arguments? J'aimerais plus de détails sur la chose que vous appelleriez.

Tout d'abord, j'ai joué avec l'opérateur spread ce matin et la plupart de mes cas d'utilisation fonctionnent bien dans la dernière version de typescript [email protected] et sur http://www.typescriptlang.org/Playground. Ce n'est donc plus un gros problème.

cependant,
Je n'aime pas l'idée de rendre tous les paramètres facultatifs juste pour pouvoir utiliser
opérateur de propagation MAIS je comprends le problème; la longueur des tableaux n'est pas connue au moment de la compilation donc
il est impossible de vérifier les paramètres au moment de la compilation.

Cependant, je pense que ce serait bien si les paramètres n'ont pas besoin d'être facultatifs et que le compilateur
Vérifiez seulement que "spread-variable" est du bon type, par exemple. nombre[]

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

Est-ce possible?

Le code suivant fonctionne dans la version actuelle de dactylographié, ce qui n'était pas le cas lorsque ce problème a été résolu.

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

Peut-être un exemple plus réaliste (qui fonctionne également de nos jours):

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: Ayant le même problème, avec le cas d'utilisation spécifique du constructeur Date :

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

Pour nous, nous utilisons des spreads pour permettre aux utilisateurs de configurer les exigences argv dans une application de base sans avoir besoin de créer leurs propres helpers. Par exemple:

{
  "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 exemple du monde réel utilisant la fonction combineLatest de https://github.com/ReactiveX/rxjs où je veux conserver la this lors de l'appel de projectFn utilisant une fonction de flèche et utiliser les paramètres de repos pour propager les arguments.

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

Actuellement je dois faire

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

FWIW, un autre exemple du monde réel tente de fusionner en profondeur un tableau d'objets en utilisant la fusion à partir de lodash:

import { merge } from 'lodash';

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

Voici un autre cas d'utilisation du monde réel; nous essayons de refactoriser le code qui ressemble à ceci:

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

Dans le légèrement plus élégant:

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

Mais l'utilisation de l'opérateur de propagation déclenche l'erreur de non-concordance de signature.

Un autre exemple

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

    }
}

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

TS2346: Les paramètres fournis ne correspondent à aucune signature de la cible d'appel.

Même problème avec les méthodes de surcharge:

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;

tandis que appelé comme

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

then: _ [ts] Les paramètres fournis ne correspondent à aucune signature de la cible de l'appel._

Donc pour l'instant, il est impossible de faire une telle chose:

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

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

Comme il produit une erreur:

Les paramètres fournis ne correspondent à aucune signature de la cible de l'appel.

Même si la valeur contient les valeurs correctes des paramètres du constructeur de date @mhegazy ? Ou je ne reçois rien?

Même si la valeur contient les valeurs correctes des paramètres du constructeur de date @mhegazy ? Ou je ne reçois rien?

C'est exact, c'est ce que ce problème suit.

Je me sens obligé de demander si je peux aider / contribuer d'une manière ou d'une autre. Si maintenant, pouvez-vous expliquer pourquoi exactement cela cause une erreur dans ce cas? Peut-il être ignoré d'une manière ou d'une autre dans la configuration?

J'ai été confronté à ce problème lorsque j'ai renommé un fichier .js en .ts . Quoi qu'il en soit, un exemple de "tous les JS valides ne sont pas des TS valides".

Je rencontre actuellement ce problème lors de la mise en œuvre de l'exemple de modèles de médias de styled-component.

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.
                }
            `
    }
), {});

Ma solution de contournement consiste à utiliser css.call , qui fonctionne au moins avec les arguments any[] type

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)}
                }
            `
    }
), {});

mêmes problèmes, mon exemple est la fonction de fusion de base:

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

existe-t-il une solution de contournement pour désactiver cette erreur au moins par fichier?

En fait, j'aimerais voir les raisons pour lesquelles cette possibilité ES6 est interrompue par la conception ou par des plans lorsqu'elle pourrait être reconsidérée. @mhegazy veuillez commenter.

Nous avons récemment apporté une modification pour permettre la diffusion dans des expressions d'appel si la cible est entièrement facultative (voir https://github.com/Microsoft/TypeScript/pull/15849). Le changement fonctionne en traitant une sortie étalée comme un ensemble infini d'arguments facultatifs.

Avec ce changement, voici l'état actuel des exemples:

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

Dans le dernier exemple, le compilateur n'a aucun moyen de valider que args satisfait les baz , car la longueur de args ne peut pas être validée statiquement.

Ce qui reste dans cette zone est de permettre aux tuples de taille connue de satisfaire des fonctions avec des arguments requis de même longueur ... mais ce n'est pas aussi simple que cela puisse paraître. par exemple:

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

J'ai le même problème que @devrelm

J'ai toujours un problème avec ça, qu'est-ce qui ne va pas?

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

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

Il donne une erreur sur le terrain de jeu dactylographié

@owlcode c'est dans TS 2.4 mais le terrain de jeu est sur TS 2.3 jusqu'à la version 2.4.

Cela semble être résolu dans TS 2.4,

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

Cependant, il semble y avoir un nouveau bogue dans TS 2.4:

TS2461: Type 'Iterable'n'est pas un type de tableau.

Cela se produit lorsque vous essayez de diffuser un itérable ( [...obj] ).

Et pourtant, un bug différent (je pense) dans 2.4.1-insiders.20170615 que je n'ai pas encore pu comprendre.

Je ne sais pas non plus comment contourner celui-ci. Diffuser nos tableaux en any[] n'aidera pas.


Peu importe, nous pouvons corriger la définition 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;
}

Et puis lancez l'objet console :

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

Cela va devoir faire pour le moment.

J'ai ouvert un PR pour cela au # 18004.

Pour l'instant, je vais devoir activer "noStrictGenericChecks" dans mon tsconfig.

Pour l'instant, je vais devoir activer "noStrictGenericChecks" dans mon tsconfig.

Je ne sais pas comment cela est lié à ce bogue ...

Je ne sais pas comment cela est lié à ce bogue.

@mhegazy Ce paramètre désactive toutes les signatures de fonction, donc je peux passer des arguments à l'aide de l'opérateur spread sans faire correspondre la quantité d'arguments (du moins pas de manière statique)

ce n'est pas ce que font --noStrictGenericChecks . Veuillez consulter https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#stricter -checking-for-generic-functions

Je viens de traverser ça.

Bien que je puisse comprendre que c'est difficile, au moins les arguments "excessifs" devraient pouvoir être identifiés.

@sandersn du point de vue du monde réel, nous refactorions une API pour accepter un seul argument ou un tableau, au lieu d'utiliser un argument rest. Ainsi, les situations où nous passions quelque chose comme foo(value, ...otherValues) n'étaient pas identifiées comme des erreurs. Plus précisément, cela semble vraiment dangereux :

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

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

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

@kitsonk pouvez-vous ouvrir un bogue séparé pour cela? Ce serait plus facile à considérer isolément et il s'agit probablement d'une petite modification des règles existantes, plutôt que d'un changement complexe.

Même si je vérifie la longueur, j'obtiens toujours cette erreur:

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

Éditer:

Pour dissiper la confusion, j'ai été redirigé d' ici , ce qui indique:

Attendu 2 arguments, mais obtenu un minimum de 0

Cette question a été considérée comme un double de cette question.

Dans mon cas, j'ai pu corriger mon erreur (plus comme un hack qu'un correctif) en permettant que rien ne soit passé à la méthode en ajoutant function otherFunc() comme l'un des initialiseurs comme ceci:

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

Cette solution de contournement est interrompue sur 2.7

Comment est-ce toujours un problème? Les opérateurs de propagation sont un moyen parfaitement conforme de travailler dans JS, donc TS devrait en tenir compte correctement.

@ jpike88 Je sais que vous voulez bien dire, mais vous ne réaliserez peut-être pas que des déclarations comme celles-ci sont contre-productives. Le problème est sur leur TODO pour les jalons 2.7 ou 2.8 il ressemble. Cela peut sembler une chose évidente à corriger, mais lorsque vous avez des milliers de choses évidentes à corriger, vous ne pouvez pas les réparer toutes en même temps et continuer à améliorer d'autres choses que l'on attend d'eux. La meilleure façon d'exprimer votre vote est de donner une réaction au post original en haut. C'est un logiciel libre après tout et ils ne nous doivent rien. Cela dit, c'est juste mon avis, un autre utilisateur
de TS comme toi 🕺

Un autre test intéressant (en fait une régression de TS 2.7) est celui-ci:

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

Cela produit

test.ts (20,9): erreur TS2557: attendu au moins 0 argument, mais a obtenu 0 ou plus.

Un autre problème que j'ai rencontré concernant l'opérateur de propagation:

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'

Bien sûr, dans ES6, je n'ai aucun problème pour répandre un tableau avec undefined inclus comme arguments et passer correctement les undefined mais il semble que TS ignore simplement les valeurs undefined quand il les répand.

Un autre exemple du monde réel, dans lequel la gestion correcte de l'opérateur de propagation dans l'appel de fonction aidera beaucoup:
J'ai des fonctions générées par NSwagStudio - générateur d'API pour C # WebApi, qui ont les mêmes paramètres (les paramètres GET sont définis dans la structure)

La fonction générée ressemble à ceci:

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

Je veux l'appeler avec la syntaxe

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

car il y a plus de fonctions avec exactement les mêmes paramètres (car elles sont générées à partir de la même classe de paramètres définie dans le backend C #). Maintenant, je dois copier le corps de la propriété tableIdentification n fois dans chaque utilisation

@smashdevcode Pour moi, la solution était d'ajouter @ ts-ignore

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

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

@ darekf77 , ou si vous dites que args est un tuple:

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

ts-aire de jeux

@ darekf77 , ou si vous dites que args est un tuple:

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

Cela fonctionne pour moi lorsque je compile du texte dactylographié dans la ligne de commande, mais pas lorsque Visual Studio Code valide le dactylographié pendant que je tape. Je ne sais pas quelle est la déconnexion ici.

Je vois que cela fait plus d'un an que jayphelps a mentionné que cela serait corrigé dans une prochaine version, mais ce problème persiste. Y a-t-il une mise à jour à ce sujet? Je sais que je pourrais utiliser @ ts-ignore, mais cela supprime TOUS les messages dactylographiés pour la fonction, ce n'est donc pas vraiment une solution appropriée.

@TidyIQ comme mentionné par tjoskar, transformez votre tableau de diffusion en tuple.

Le tableau n'est pas de longueur fixe, donc cela ne fonctionnera pas.

Un transtypage fonctionnera en ce qui concerne le compilateur, même s'il est inexact. Je suis d'accord que ce n'est pas la meilleure solution.

(Cette question devrait probablement être déplacée vers le débordement de pile (ou similaire))

@TidyIQ , si le tableau n'a pas de longueur fixe, le compilateur ne peut pas dire si le tableau convient ou non.

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. 

Donc, si le tableau est de longueur dynamique, les arguments devraient l'être également:

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

Terrain de jeux

Malheureusement, cela ne fonctionnera pas non plus car certains de mes arguments sont de longueur fixe.

Peut-être que si je publie simplement le code, vous pourriez voir le problème.

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 , je ne suis pas sûr de suivre. Que se passe-t-il si stateList est un tableau vide? Dans ce cas, action.payload.value sera-t-il passé comme key ?

Cela ne devrait pas fonctionner:

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

Transtypez la valeur de propagation en tant que ParameterType de la fonction à laquelle vous passez des arguments.

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

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

type AddParams = Parameters<typeof add>

add(...(values) as AddParams)

@ mateja176 Cela semble également fonctionner et pourrait mieux convenir à certains cas d'utilisation.

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

ou

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

J'utilise un type d'assistance pour cela pour gérer des tableaux arbitraires sans avoir à les taper explicitement:

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

Il peut être utilisé comme ceci:

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


Explication détaillée pour les débutants

La dissection suivante du type NonEmptyArray explique son fonctionnement en détail:

# | Partie | Explication
- | - | -
(1) | type NonEmptyArray | Le nom du type d'assistance
(2) | <T | Le type d'assistance prend un paramètre de type générique T .
(3) | extends any[]> | Pour être accepté par le vérificateur de type, ce paramètre de type T doit être un type de tableau.
(4) | T extends (infer U)[] ? | Notre type d'assistance est un type conditionnel qui vérifie si T est réellement un type de tableau.
Nous avons déclaré T comme type de tableau dans (3), donc cette condition passe toujours, mais l'utilisation du conditionnel nous permet de laisser TypeScript infer le type que le tableau T est fait de, et nous appelons ce type U .
(5) | [U, ...U[]] | Nous pouvons maintenant assembler le type résultant: un tableau où la première entrée est de type U et les entrées restantes (0 ou plus) sont également de type U .
En raison de cette notation de tuple spécifique, TypeScript est conscient qu'il existe au moins un élément.
(6) | : never | Ceci est juste nécessaire pour compléter syntaxiquement le conditionnel. Rappelez-vous: le conditionnel est juste une astuce pour extraire le type U , et il passe toujours. Par conséquent, nous pouvons ignorer en toute sécurité la branche "else" en produisant never .


Maintenant, si nous faisons cela ...

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

... ce qui suit se produira:

  • typeof values est le type que TypeScript a déduit pour le tableau values , qui est un tableau de nombres: number[] .
  • Cela signifie que nous passons number[] comme T . (2/3)
  • T est en effet un type de tableau, donc, nous pouvons en déduire U , soit number . (4)
  • Maintenant que nous savons que U est un number , nous générons le type [number, ...number[]] . (5)

@tjoskar change ton code en

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

( aire de jeux )
Et l'erreur est de retour.

Étonnamment, si vous deviez changer la dernière ligne en foo(3, ...args); - il n'y aura pas d'erreur.

J'ai l'impression que cela ne fonctionne toujours pas. Voici mon exemple

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

Le type de props.onSetValue ne devrait pas vraiment avoir d'importance, car je prends simplement le type de paramètres et le passe à la fonction dont j'ai obtenu le type et cela donne toujours l'erreur Expected 2 arguments, but got 0 or more. .

Lien Playground

Voici une forme réduite de l'exemple de @ Haaxor1689 :
Lien Playground

Je n'arrive toujours pas à le faire fonctionner

c'est ma solution de contournement temporaire

class Board {
  private events: Events

  public on(...args: Parameters<this['events']['on']>) {
    this.events.on.call(this.events, ...args)
  }
}
Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

remojansen picture remojansen  ·  3Commentaires

jbondc picture jbondc  ·  3Commentaires

MartynasZilinskas picture MartynasZilinskas  ·  3Commentaires

siddjain picture siddjain  ·  3Commentaires

manekinekko picture manekinekko  ·  3Commentaires