Festlegen des Standardwerts für das als Argument übergebene TypeScript-Objekt


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

Ich hatte mir vorgestellt, dass so etwas funktionieren könnte:

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

Wenn dies einfache Argumente wären, könnten Sie dies natürlich tun mit:

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

sayName('bob');

Und in Coffeescript haben Sie Zugriff auf den Operator für bedingte Existenz, also können Sie Folgendes tun:

param.lastName ?= 'smith'

Welches kompiliert zum Javascript:

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

Ihre vorgeschlagene Lösung params.lastName = params.lastName || 'smith';ist eigentlich ziemlich in Ordnung - sie behandelt leere Zeichenfolgen, undefinierte Zeichenfolgen und Nullwerte.
Fenton

@SteveFenton Und alles Falsche. Bei einem Nachnamen ist das in Ordnung, aber im Allgemeinen keine gute Idee. Aus diesem Grund übersetzt Typescript Standardwerte in if(typeof x === "undefined") { … }. Nicht, dass Sie das nicht wissen, sondern nur auf den allgemeinen Fall für das OP hinweisen.
Ingo Bürk

1
@ IngoBürk wahr, aber aufgrund lastName?: stringdessen kann es immer nur so sein, wie SteveFenton sagte "behandelt leere Zeichenfolgen, undefinierte Zeichenfolgen und Nullwerte".
AJP

@AJP Innerhalb von Typescript ja. Aber das ist nur Kompilierungszeit. Wie auch immer, wie gesagt, ich möchte nur auf ein allgemeines Szenario hinweisen :)
Ingo Bürk

2
Stimmen Sie Steve hier zu. Sehr häufig ist es besser, ein einziges Konfigurationsargument zu haben, anstatt z. B. 10 Argumente. In diesem Fall params.lastName = params.lastName || 'smith';ist das Muster, das ich benutze
Basarat

Antworten:


210

Eigentlich scheint es jetzt einen einfachen Weg zu geben. Der folgende Code funktioniert in TypeScript 1.5:

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

sayName({ first: 'Bob' });

Der Trick besteht darin, zuerst in Klammern zu setzen, welche Schlüssel Sie aus dem Argumentobjekt auswählen möchten, mit key=valueetwaigen Standardeinstellungen. Folgen Sie dem mit :und einer Typdeklaration.

Dies unterscheidet sich ein wenig von dem, was Sie versucht haben, da Sie anstelle eines intakten paramsObjekts dereferenzierte Variablen haben.

Wenn Sie es optional machen möchten, etwas an die Funktion zu übergeben, fügen Sie ein ?für alle Schlüssel im Typ hinzu und fügen Sie ={}nach der Typdeklaration einen Standardwert von hinzu :

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

sayName();

Diese Lösung bietet eine interessante Code-Hinweis- / Intellisense-Funktion, da die Parameter vollständig zerstört sind. Ich würde nicht erwarten, diesen Stil in einem Einstellungsobjekt mit mehr als ein paar Parametern wie im Beispiel zu sehen.
WiredPrairie

3
Ist es auch möglich, diese Lösung neu zu schreiben, um stattdessen eine Schnittstelle / Klasse wie "sayNameSettings" zu verwenden?
Stef Heyenrath

4
Während dies funktioniert, macht es die Destrukturierung der Argumente auf diese Weise schwierig, IMO zu folgen.
PW Kad

1
Sie können das Schlüsselwort 'as' verwenden (meiner Meinung nach ist es besser lesbar), wie {first = 'Bob', last = 'Smith'} als {first?: string; last?: string} aber idealerweise sollten Sie eine Schnittstelle für diese Fälle erstellen ...
Fröhlich

1
Gibt es eine Möglichkeit, das Optionsobjekt an eine andere Funktion zu übergeben?
Dylanthepiguy

50

Typescript unterstützt jetzt Standardparameter:

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

Durch Hinzufügen eines Standardwerts können Sie auch die Typdeklaration weglassen, da sie aus dem Standardwert abgeleitet werden kann:

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

sayName('Bob');

21
Wie trifft dies auf die Frage des OP bezüglich des Standardwerts für das als Argument übergebene TypeScript-Objekt zu? Sie sollten ein Beispiel mit einem Objektargument zeigen.
Demisx

9
Dies ist nicht der Fall, aber ich fand diese Frage, als ich nach Möglichkeiten suchte, Standardparameter in Typoskript im Allgemeinen bereitzustellen, und keine der Antworten ging darauf ein. Ich habe diese Antwort auch gepostet, bevor ich die subtile "Objekt" -Parameterklärung bemerkte.
Encrest

27

Objekt Destrukturierung die Parameter Objekt ist , was viele der Antworten oben streben und Typoskript hat jetzt die Methoden anstelle es viel leichter zu lesen und intuitiv verstehen.

Grundlagen der Destrukturierung: Durch die Destrukturierung eines Objekts können Sie Eigenschaften eines Objekts anhand des Schlüsselnamens auswählen. Sie können so wenige oder so viele Eigenschaften definieren, wie Sie möchten, und die Standardwerte werden durch eine grundlegende Syntax von festgelegt let {key = default} = object.

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

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

Das Schreiben einer Schnittstelle, eines Typs oder einer Klasse für das Parameterobjekt verbessert die Lesbarkeit.

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
Ich denke, das ist die beste Antwort auf die Frage!
Gezim

24

Nein, TypeScript bietet keine natürliche Möglichkeit, Standardeinstellungen für Eigenschaften eines Objekts festzulegen, das so definiert ist, dass eines einen Standard hat und das andere nicht. Sie könnten eine reichhaltigere Struktur definieren:

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

    }
}

Und verwenden Sie dies anstelle der Inline-Typdefinition.

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

So etwas kann man leider nicht machen:

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

} 

Da es nur den Standard festgelegt würde , wenn nameist undefined.


Ich denke, dies ist die beste Antwort auf diese Frage und sollte als die richtige Antwort markiert werden.
Kapad

16

Dies kann eine gute Möglichkeit sein, ohne lange Konstruktoren zu verwenden

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 die Standardeinstellungen werden in der zweiten und dritten Zeile "Bob" und "Smith"
Cameron

3

Hier ist etwas zu versuchen, Schnittstelle und Destrukturierung mit Standardwerten zu verwenden. Bitte beachten Sie, dass "lastName" optional ist.

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

Ohne Destrukturierung können Sie Standardparameter erstellen und übergeben

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

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

sayName({ ...defaultName, firstName: 'Bob' })
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.