Ustawienie wartości domyślnej dla obiektu TypeScript przekazywanego jako argument


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

Wyobraziłem sobie, że coś takiego może działać:

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

Oczywiście, gdyby były to proste argumenty, można to zrobić za pomocą:

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

sayName('bob');

A w coffeescript masz dostęp do operatora warunkowego istnienia, dzięki czemu możesz:

param.lastName ?= 'smith'

Który kompiluje się w javascript:

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

Sugerowane rozwiązanie params.lastName = params.lastName || 'smith';jest w rzeczywistości całkiem dobre - obsługuje puste ciągi, niezdefiniowane ciągi i wartości zerowe.
Fenton

@ SteveFenton I cokolwiek innego. W przypadku nazwiska jest w porządku, ale generalnie nie jest to dobry pomysł. Dlatego maszynopis tłumaczy wartości domyślne na if(typeof x === "undefined") { … }. Nie dlatego, że tego nie wiesz, ale po prostu wskazując ogólny przypadek PO.
Ingo Bürk

1
@ IngoBürk prawda, ale z tego powodu lastName?: stringmoże być tylko tak, jak powiedział SteveFenton „obsługuje puste ciągi, niezdefiniowane ciągi i wartości zerowe”.
AJP

@AJP Wewnątrz maszynopisu, tak. Ale to tylko czas kompilacji. Tak czy inaczej, jak już powiedziałem, po prostu wskazując ogólny scenariusz przypadku :)
Ingo Bürk

2
Zgadzam się ze Stevem tutaj. Dość często lepiej jest mieć pojedynczy argument konfiguracji zamiast np. 10 argumentów. W tym przypadku params.lastName = params.lastName || 'smith';używam wzoru
basarat

Odpowiedzi:


211

W rzeczywistości wydaje się, że istnieje teraz prosty sposób. Poniższy kod działa w TypeScript 1.5:

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

sayName({ first: 'Bob' });

Sztuczka polega na tym, aby najpierw wstawić w nawiasach klucze, które chcesz wybrać z obiektu argumentu, key=valuedla wszystkich wartości domyślnych. Postępuj zgodnie z tym za :pomocą deklaracji typu.

Jest to trochę inne niż to, co próbujesz zrobić, ponieważ zamiast mieć nienaruszony paramsobiekt, zamiast tego masz zmienione wartości odniesienia.

Jeśli chcesz, aby opcjonalne było przekazywanie czegokolwiek do funkcji, dodaj a ?dla wszystkich kluczy tego typu i dodaj domyślną wartość ={}po deklaracji typu:

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

sayName();

To rozwiązanie zapewnia interesującą funkcję podpowiedzi / inteligencji kodu, ponieważ pokazuje parametry całkowicie zniszczone. Nie spodziewałbym się, że zobaczę ten styl w obiekcie ustawień z więcej niż kilkoma parametrami, jak w przykładzie.
WiredPrairie,

3
Czy można również przepisać to rozwiązanie, aby zamiast tego użyć interfejsu / klasy, takich jak „sayNameSettings”?
Stef Heyenrath

4
Podczas gdy to działa, destrukcja argumentów w ten sposób utrudnia śledzenie IMO.
PW Kad

1
możesz użyć słowa kluczowego „jako” (moim zdaniem jest bardziej czytelne), takiego jak {first = „Bob”, last = „Smith”} jako {first ?: string; last ?: string}, ale najlepiej utworzyć interfejs do obsługi tych przypadków ...
Frohlich,

1
Czy istnieje sposób na przekazanie obiektu opcji do innej funkcji?
Dylanthepiguy

53

Maszynopis obsługuje teraz parametry domyślne:

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

Ponadto dodanie wartości domyślnej pozwala pominąć deklarację typu, ponieważ można ją wywnioskować z wartości domyślnej:

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

sayName('Bob');

22
Jak to się odnosi do pytania OP dotyczącego domyślnej wartości obiektu TypeScript przekazanego jako argument? Powinieneś pokazać przykład z argumentem obiektowym.
demisx

9
Tak nie jest, ale znalazłem to pytanie, kiedy szukałem sposobu na podanie domyślnych parametrów w maszynopisie i żadna z odpowiedzi na to nie rozwiązała. Opublikowałem również tę odpowiedź, zanim zauważyłem subtelne wyjaśnienie parametrów „obiektu”.
zaatakuje

29

Destrukcja obiektu Obiekt parametru jest tym, do czego dąży wiele powyższych odpowiedzi, a Maszynopis ma teraz metody, które znacznie ułatwiają czytanie i intuicyjne zrozumienie.

Podstawy destrukcji: poprzez destrukcję obiektu możesz wybrać właściwości obiektu według nazwy klucza. Możesz zdefiniować mniej lub więcej właściwości, które chcesz, a wartości domyślne są ustawiane przez podstawową składnię let {key = default} = object.

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

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

Napisanie interfejsu, typu lub klasy dla obiektu parametru poprawia czytelność.

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
Myślę, że to najlepsza odpowiedź na pytanie!
Gezim

24

Nie, TypeScript nie ma naturalnego sposobu ustawiania wartości domyślnych dla właściwości obiektu zdefiniowanego w taki sposób, w którym jeden ma wartość domyślną, a drugi nie. Możesz zdefiniować bogatszą strukturę:

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

    }
}

I użyj tego zamiast definicji typu wbudowanego.

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

Niestety nie możesz zrobić czegoś takiego:

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

} 

Ponieważ ustawiłby tylko domyślnie, gdyby namebył undefined.


Myślę, że to najlepsza odpowiedź na to pytanie i powinna zostać oznaczona jako poprawna odpowiedź.
kapad

16

Może to być dobry sposób na zrobienie tego, co nie wymaga długich konstruktorów

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 wartości domyślne są ustawione w drugiej i trzeciej linii, „Bob” i „Smith”
Cameron

3

Oto coś do wypróbowania, używając interfejsu i destrukcji z wartościami domyślnymi. Pamiętaj, że „nazwisko” jest opcjonalne.

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

Bez destrukcji możesz utworzyć parametry domyślne i przekazać je

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

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

sayName({ ...defaultName, firstName: 'Bob' })
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.