Définition de la valeur par défaut pour l'objet TypeScript passé en argument


224
function sayName(params: {firstName: string; lastName?: string}) {
    params.lastName = params.lastName || 'smith';  // <<-- any better alternative to this?
    var name = params.firstName + params.lastName
    alert(name);
}

sayName({firstName: 'bob'});

J'avais imaginé que quelque chose comme ça pourrait fonctionner:

function sayName(params: {firstName: string; lastName: string = 'smith'}) {

Évidemment, s'il s'agissait d'arguments simples, vous pourriez le faire avec:

function sayName(firstName: string, lastName = 'smith') {
    var name = firstName + lastName;
    alert(name);
}

sayName('bob');

Et dans coffeescript, vous avez accès à l'opérateur d'existence conditionnelle, vous pouvez donc faire:

param.lastName ?= 'smith'

Qui compile au javascript:

if (param.lastName == null) {
    param.lastName = 'smith';
}

Votre solution suggérée params.lastName = params.lastName || 'smith';est en fait plutôt bonne - elle gère les chaînes vides, les chaînes non définies et les valeurs nulles.
— Fenton

@SteveFenton Et tout ce qui est faux. C'est bien dans le cas d'un nom de famille, mais ce n'est généralement pas une bonne idée. C'est pourquoi Typescript traduit les valeurs par défaut en if(typeof x === "undefined") { … }. Non pas que vous ne le sachiez pas, mais simplement en soulignant le cas général du PO.
— Ingo Bürk

1
@ IngoBürk est vrai, mais à cause de lastName?: stringcela, il ne peut l'être que comme l'a dit SteveFenton "gère les chaînes vides, les chaînes non définies et les valeurs nulles".
— AJP

@AJP Dans Typescript, oui. Mais ce n'est que la compilation. Quoi qu'il en soit, comme je l'ai dit, il suffit de signaler un scénario général :)
— Ingo Bürk

2
D'accord avec Steve ici. Il est généralement préférable d'avoir un seul argument de configuration au lieu de 10 arguments par exemple. Dans ce cas, params.lastName = params.lastName || 'smith';c'est le modèle que j'utilise
— basarat

Réponses:


233

En fait, il semble maintenant y avoir un moyen simple. Le code suivant fonctionne dans TypeScript 1.5:

function sayName({ first, last = 'Smith' }: {first: string; last?: string }): void {
  const name = first + ' ' + last;
  console.log(name);
}

sayName({ first: 'Bob' });

L'astuce consiste d'abord à mettre entre parenthèses les clés que vous voulez choisir dans l'objet argument, avec key=valuepour les valeurs par défaut. Suivez cela avec la :déclaration de type et.

C'est un peu différent de ce que vous essayiez de faire, car au lieu d'avoir un paramsobjet intact , vous avez à la place des variables déréférencées.

Si vous souhaitez rendre facultatif de passer quoi que ce soit à la fonction, ajoutez un ?pour toutes les clés du type et ajoutez une valeur par défaut ={}après la déclaration de type:

function sayName({first='Bob',last='Smith'}: {first?: string; last?: string}={}){
    var name = first + " " + last;
    alert(name);
}

sayName();

Cette solution crée une fonctionnalité intéressante d' indication de code / d'intellisense car elle montre les paramètres entièrement déstructurés. Je ne m'attendrais pas à voir ce style dans un objet de paramètres avec plus de quelques paramètres comme dans l'exemple.
— WiredPrairie

3
Est-il également possible de réécrire cette solution pour utiliser à la place une interface / classe comme "sayNameSettings"?
— Stef Heyenrath

4
Bien que cela fonctionne, déstructurer les arguments de cette façon rend difficile le suivi de l'OMI.
— PW Kad

1
vous pouvez utiliser le mot clé 'as' (à mon avis, il est plus lisible), comme {first = 'Bob', last = 'Smith'} comme {first ?: string; last ?: string} mais idéalement, vous devriez créer une interface pour gérer ce cas ...
— Frohlich

1
Existe-t-il un moyen de passer l'objet d'options à une autre fonction?
— Dylanthepiguy

55

Typescript prend désormais en charge les paramètres par défaut:

https://www.typescriptlang.org/docs/handbook/functions.html

De plus, l'ajout d'une valeur par défaut vous permet d'omettre la déclaration de type, car elle peut être déduite de la valeur par défaut:

function sayName(firstName: string, lastName = "Smith") {
  const name = firstName + ' ' + lastName;
  alert(name);
}

sayName('Bob');

27
Comment cela s'applique-t-il à la question de l'OP concernant la valeur par défaut de l'objet TypeScript passé en argument? Vous devez montrer un exemple avec un argument d'objet.
— demisx le

11
Ce n'est pas le cas, mais j'ai trouvé cette question lorsque je cherchais comment fournir des paramètres par défaut dans le typographie en général, et aucune des réponses n'a abordé cela. J'ai également posté cette réponse avant de remarquer la clarification subtile du paramètre "objet".
— encrest le

32

La déstructuration d'objet de l'objet paramètre est ce que la plupart des réponses ci-dessus visent et Typescript a maintenant les méthodes en place pour le rendre beaucoup plus facile à lire et à comprendre intuitivement.

Principes de base de la destruction : en déstructurant un objet, vous pouvez choisir les propriétés d'un objet par nom de clé. Vous pouvez définir autant ou autant de propriétés que vous le souhaitez, et les valeurs par défaut sont définies par une syntaxe de base de let {key = default} = object.

let {firstName, lastName = 'Smith'} = myParamsObject;

//Compiles to:
var firstName = myParamsObject.firstName, 
_a = myParamsObject.lastName, 
lastName = _a === void 0 ? 'Smith' : _a;

L'écriture d'une interface, d'un type ou d'une classe pour l'objet paramètre améliore la lisibilité.

type FullName = {
  firstName: string;
   
  /** @default 'Smith' */
  lastName ? : string;
}

function sayName(params: FullName) {

  // Set defaults for parameter object
  var { firstName, lastName = 'Smith'} = params;

  // Do Stuff
  var name = firstName + " " + lastName;
  alert(name);
}

// Use it
sayName({
  firstName: 'Bob'
});


3
Je pense que c'est la meilleure réponse à la question!
— Gezim

27

Non, TypeScript n'a pas de moyen naturel de définir les valeurs par défaut pour les propriétés d'un objet défini comme celui où l'un a une valeur par défaut et l'autre pas. Vous pouvez définir une structure plus riche:

class Name {
    constructor(public first : string, 
        public last: string = "Smith") {

    }
}

Et utilisez cela à la place de la définition de type en ligne.

function sayName(name: Name) {
    alert(name.first + " " + name.last);
}

Vous ne pouvez malheureusement pas faire quelque chose comme ça:

function sayName(name : { first: string; last?:string } 
       /* and then assign a default object matching the signature */  
       = { first: null, last: 'Smith' }) {

} 

Comme il ne définirait la valeur par défaut que si namec'était undefined.


1
Je pense que c'est la meilleure réponse à cette question et devrait être marquée comme la bonne réponse.
— kapad du

16

Cela peut être une bonne façon de le faire qui n'implique pas de longs constructeurs

class Person {
    firstName?: string = 'Bob';
    lastName?: string = 'Smith';

    // Pass in this class as the required params
    constructor(params: Person) {
        // object.assign will overwrite defaults if params exist
        Object.assign(this, params)
    }
}

// you can still use the typing 
function sayName(params: Person){ 
    let name = params.firstName + params.lastName
    alert(name)
}

// you do have to call new but for my use case this felt better
sayName(new Person({firstName: 'Gordon'}))
sayName(new Person({lastName: 'Thomas'}))

2
@PWKad les valeurs par défaut sont définies sur la deuxième et la troisième ligne, "Bob" et "Smith"
— Cameron le

1

Voici quelque chose à essayer, en utilisant l'interface et la déstructuration avec les valeurs par défaut. Veuillez noter que "lastName" est facultatif.

interface IName {
  firstName: string
  lastName?: string
}

function sayName(params: IName) {
  const { firstName, lastName = "Smith" } = params
  const fullName = `${firstName} ${lastName}`

  console.log("FullName-> ", fullName)
}

sayName({ firstName: "Bob" })

0

Sans déstructuration, vous pouvez créer un paramètre par défaut et le transmettre

interface Name {
   firstName: string;
   lastName: string;
}

export const defaultName extends Omit<Name, 'firstName'> {
    lastName: 'Smith'
}

sayName({ ...defaultName, firstName: 'Bob' })
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.