L'impostazione del valore predefinito per l'oggetto TypeScript è passata come argomento


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

Avevo immaginato che qualcosa del genere potesse funzionare:

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

Ovviamente se questi fossero semplici argomenti, potresti farlo con:

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

sayName('bob');

E in coffeescript hai accesso all'operatore dell'esistenza condizionale, quindi puoi fare:

param.lastName ?= 'smith'

Che compila nel javascript:

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

La soluzione suggerita in params.lastName = params.lastName || 'smith';realtà è piuttosto corretta: gestisce stringhe vuote, stringhe non definite e valori null.
Fenton,

@SteveFenton E qualsiasi cosa falsa. Va bene nel caso di un cognome, ma generalmente non è una buona idea. Ecco perché Typescript traduce i valori predefiniti in if(typeof x === "undefined") { … }. Non che tu non lo sappia, ma indica solo il caso generale del PO.
Ingo Bürk,

1
@ IngoBürk vero, ma a causa lastName?: stringsua può essere sempre e solo come ha detto SteveFenton "gestisce stringhe vuote, stringhe indefinite e valori nulli".
AJP,

@AJP All'interno di Typescript, sì. Ma questo è solo tempo di compilazione. Ad ogni modo, come ho detto, sottolineando uno scenario generale :)
Ingo Bürk,

2
D'accordo con Steve qui. Abbastanza comunemente è meglio avere un singolo argomento di configurazione invece di 10 argomenti. In questo caso params.lastName = params.lastName || 'smith';è lo schema che uso
basarat il

Risposte:


211

In realtà, ora sembra esserci un modo semplice. Il seguente codice funziona in TypeScript 1.5:

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

sayName({ first: 'Bob' });

Il trucco è prima di tutto mettere tra parentesi quali chiavi si vogliono scegliere dall'argomento argomento, con key=valueeventuali valori predefiniti. Seguilo con la :dichiarazione di tipo e.

Questo è un po 'diverso da quello che stavi cercando di fare, perché invece di avere un paramsoggetto intatto , hai invece delle variabili senza riferimenti.

Se si desidera rendere facoltativo il passaggio di qualcosa alla funzione, aggiungere a ?per tutti i tasti nel tipo e aggiungere un valore predefinito ={}dopo la dichiarazione del tipo:

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

sayName();

Tale soluzione crea una funzionalità di suggerimento del codice / intellisense interetsting in quanto mostra i parametri completamente destrutturati. Non mi aspetterei di vedere quello stile in un oggetto impostazioni con più di alcuni parametri come nell'esempio.
WiredPrairie,

3
È anche possibile riscrivere questa soluzione per utilizzare invece un'interfaccia / classe come "sayNameSettings"?
Stef Heyenrath,

4
Mentre funziona, distruggere gli argomenti in questo modo rende difficile seguire l'IMO.
PW Kad,

1
puoi usare la parola chiave "as" (secondo me è più leggibile), come {first = 'Bob', last = 'Smith'} come {first ?: string; last ?: string} ma idealmente dovresti creare un'interfaccia per gestire questi casi ...
Frohlich

1
C'è un modo per passare l'oggetto opzioni a un'altra funzione?
Dylanthepiguy,

53

Typescript ora supporta i parametri predefiniti:

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

Inoltre, l'aggiunta di un valore predefinito consente di omettere la dichiarazione del tipo, poiché può essere dedotta dal valore predefinito:

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

sayName('Bob');

22
Come si applica alla domanda dell'OP relativa al valore predefinito per l'oggetto TypeScript passato come argomento? Dovresti mostrare un esempio con un argomento object.
Demisx,

9
Non lo è, ma ho trovato questa domanda mentre cercavo come fornire i parametri predefiniti in dattiloscritto in generale, e nessuna delle risposte ha risposto a questo. Ho anche pubblicato questa risposta prima di notare il sottile chiarimento dei parametri "oggetto".
Encrest

29

Distruzione dell'oggetto l'oggetto parametro è ciò a cui molte delle risposte sopra puntano e Typescript ora ha i metodi in atto per rendere molto più facile la lettura e la comprensione intuitiva.

Nozioni di base sulla distruzione: distruggendo un oggetto, è possibile scegliere le proprietà di un oggetto in base al nome della chiave. È possibile definire come poche o quante delle proprietà desiderate e i valori predefiniti sono impostati da una sintassi di base di let {key = default} = object.

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

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

Scrivere un'interfaccia, un tipo o una classe per l'oggetto parametro migliora la leggibilità.

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
Penso che questa sia la migliore risposta alla domanda!
Gezim,

24

No, TypeScript non ha un modo naturale di impostare i valori predefiniti per le proprietà di un oggetto definito come quello in cui uno ha un valore predefinito e l'altro no. Potresti definire una struttura più ricca:

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

    }
}

E usalo al posto della definizione del tipo inline.

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

Purtroppo non puoi fare qualcosa del genere:

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

} 

Come impostarebbe il valore predefinito solo se lo namefosse undefined.


Penso che questa sia la migliore risposta a questa domanda e debba essere contrassegnata come la risposta corretta.
Kapad,

16

Questo può essere un bel modo per farlo che non coinvolge costruttori lunghi

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 le impostazioni predefinite sono impostate sulla seconda e terza riga, "Bob" e "Smith"
Cameron

3

Ecco qualcosa da provare, utilizzando l'interfaccia e la destrutturazione con valori predefiniti. Si noti che "lastName" è facoltativo.

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

Senza la destrutturazione, è possibile creare parametri predefiniti e passarli

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

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

sayName({ ...defaultName, firstName: 'Bob' })
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.