Establecer el valor predeterminado para el objeto TypeScript pasado como argumento


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

Había imaginado que algo como esto podría funcionar:

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

Obviamente, si estos fueran argumentos simples, podría hacerlo con:

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

sayName('bob');

Y en coffeescript tienes acceso al operador de existencia condicional, así que puedes hacer:

param.lastName ?= 'smith'

Que se compila al javascript:

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

Su solución sugerida params.lastName = params.lastName || 'smith';es bastante buena: maneja cadenas vacías, cadenas indefinidas y valores nulos.
— Fenton

@SteveFenton Y cualquier cosa falsa. Está bien en el caso de un apellido, pero generalmente no es una buena idea. Es por eso que Typecript traduce los valores predeterminados a if(typeof x === "undefined") { … }. No es que no lo sepas, sino solo señalar el caso general del OP.
— Ingo Bürk

1
@ IngoBürk es cierto, pero debido a lastName?: stringesto solo puede ser como SteveFenton dijo "maneja cadenas vacías, cadenas indefinidas y valores nulos".
— AJP

@AJP Dentro del mecanografiado, sí. Pero eso es solo tiempo de compilación. De cualquier manera, como dije, solo señalando un escenario de caso general :)
— Ingo Bürk

2
De acuerdo con Steve aquí. Comúnmente, es mejor tener un único argumento de configuración en lugar de, por ejemplo, 10 argumentos. En este caso params.lastName = params.lastName || 'smith';es el patrón que uso
— basarat

Respuestas:


211

En realidad, parece que ahora hay una manera simple. El siguiente código funciona en TypeScript 1.5:

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

sayName({ first: 'Bob' });

El truco consiste en poner entre paréntesis qué teclas desea elegir del objeto de argumento, key=valuepara cualquier valor predeterminado. Siga eso con la :y una declaración de tipo.

Esto es un poco diferente de lo que estaba tratando de hacer, porque en lugar de tener un intacto params objeto , tiene variables desreferenciadas.

Si desea que sea opcional pasar cualquier cosa a la función, agregue un ?para todas las teclas en el tipo y agregue un valor predeterminado ={}después de la declaración de tipo:

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

sayName();

Esa solución crea una característica de intestinging de código / intellisense, ya que muestra los parámetros completamente desestructurados. No esperaría ver ese estilo en un objeto de configuración con más de unos pocos parámetros como en el ejemplo.
— WiredPrairie

3
¿También es posible reescribir esta solución para usar una interfaz / clase como "sayNameSettings" en su lugar?
— Stef Heyenrath

44
Si bien esto funciona, la desestructuración de los argumentos de esta manera hace que sea difícil seguir la OMI.
— PW Kad

1
puede usar la palabra clave 'como' (en mi opinión es más legible), como {first = 'Bob', last = 'Smith'} como {first ?: string; last ?: string} pero idealmente deberías crear una interfaz para manejar estos casos ...
— Frohlich

1
¿Hay alguna manera de pasar el objeto de opciones a otra función?
— Dylanthepiguy

53

Typecript admite parámetros predeterminados ahora:

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

Además, agregar un valor predeterminado le permite omitir la declaración de tipo, ya que se puede inferir del valor predeterminado:

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

sayName('Bob');

22
¿Cómo se aplica esto a la pregunta del OP con respecto al valor predeterminado para el objeto TypeScript pasado como argumento? Debería mostrar un ejemplo con un argumento objeto.
— retiro el

9
No lo hace, pero encontré esta pregunta cuando buscaba cómo proporcionar parámetros predeterminados en mecanografiado en general, y ninguna de las respuestas abordaba eso. También publiqué esta respuesta antes de notar la sutil aclaración del parámetro "objeto".
— encierro el

29

El objetivo de la desestructuración del objeto de parámetro es el objetivo de muchas de las respuestas anteriores, y ahora mecanografiado tiene los métodos establecidos para que sea mucho más fácil de leer y entender intuitivamente.

Conceptos básicos de desestructuración : al desestructurar un objeto, puede elegir propiedades de un objeto por nombre de clave. Puede definir tan pocas o tantas de las propiedades que desee, y los valores predeterminados se establecen mediante una sintaxis básica 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;

Escribir una interfaz, tipo o clase para el objeto de parámetro mejora la legibilidad.

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
¡Creo que esta es la mejor respuesta a la pregunta!
— Gezim

24

No, TypeScript no tiene una forma natural de establecer valores predeterminados para las propiedades de un objeto definido de esa manera donde uno tiene un valor predeterminado y el otro no. Podría definir una estructura más rica:

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

    }
}

Y use eso en lugar de la definición de tipo en línea.

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

No puedes hacer algo como esto desafortunadamente:

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

} 

Como solo establecería el valor predeterminado si namefuera undefined.


Creo que esta es la mejor respuesta a esta pregunta y debe marcarse como la respuesta correcta.
— kapad

16

Esta puede ser una buena manera de hacerlo que no involucra constructores largos

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 los valores predeterminados se establecen en la segunda y tercera línea, "Bob" y "Smith"
— Cameron

3

Aquí hay algo para probar, usando la interfaz y la desestructuración con valores predeterminados. Tenga en cuenta que "apellido" es opcional.

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

Sin desestructuración, puede crear parámetros predeterminados y pasarlos

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

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

sayName({ ...defaultName, firstName: 'Bob' })
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.