Đặt giá trị mặc định cho đối tượng TypeScript được truyền làm đối số


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

Tôi đã tưởng tượng một cái gì đó như thế này có thể hoạt động:

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

Rõ ràng nếu đây là những lý lẽ đơn giản bạn có thể làm điều đó với:

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

sayName('bob');

Và trong coffeescript bạn có quyền truy cập vào toán tử tồn tại có điều kiện để có thể làm:

param.lastName ?= 'smith'

Biên dịch nào cho javascript:

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

Giải pháp params.lastName = params.lastName || 'smith';được đề xuất của bạn thực sự khá ổn - nó xử lý các chuỗi rỗng, chuỗi không xác định và giá trị null.
Fenton

@SteveFenton Và bất cứ điều gì giả. Nó tốt trong trường hợp của tên cuối cùng, nhưng nói chung không phải là một ý tưởng tốt. Đó là lý do tại sao Typecript dịch các giá trị mặc định thành if(typeof x === "undefined") { … }. Không phải là bạn không biết điều đó, mà chỉ nêu ra trường hợp chung cho OP.
Ingo Bürk

1
@ IngoBürk đúng, nhưng do lastName?: stringnó chỉ có thể là như SteveFenton đã nói "xử lý các chuỗi rỗng, chuỗi không xác định và giá trị null".
AJP

@AJP Trong Bản đánh máy, có. Nhưng đó chỉ là thời gian biên dịch. Dù bằng cách nào, như tôi đã nói, chỉ nêu ra một kịch bản trường hợp chung :)
Ingo Bürk

2
Đồng ý với steve ở đây. Thông thường, tốt hơn là có một đối số cấu hình duy nhất thay vì 10 đối số. Trong trường hợp params.lastName = params.lastName || 'smith';này là mẫu tôi sử dụng
basarat

Câu trả lời:


210

Trên thực tế, có một cách đơn giản. Đoạn mã sau hoạt động trong TypeScript 1.5:

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

sayName({ first: 'Bob' });

Mẹo đầu tiên là đặt trong ngoặc những phím nào bạn muốn chọn từ đối tượng đối số, với key=valuebất kỳ giá trị mặc định nào. Thực hiện theo đó với :và một khai báo loại.

Điều này khác một chút so với những gì bạn đã cố gắng thực hiện, vì thay vì có một paramsđối tượng nguyên vẹn , thay vào đó bạn có các biến được quy định.

Nếu bạn muốn làm cho nó tùy chọn để chuyển bất cứ thứ gì vào hàm, hãy thêm một ?cho tất cả các khóa trong loại và thêm mặc định ={}sau khi khai báo kiểu:

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

sayName();

Giải pháp mà làm cho một interetsting tính năng mã gợi ý / IntelliSense vì nó cho thấy các thông số destructured đầy đủ. Tôi sẽ không thấy kiểu đó trong một đối tượng cài đặt có nhiều hơn một vài tham số như trong ví dụ.
WiredPrairi

3
Cũng có thể viết lại giải pháp này để sử dụng một giao diện / lớp như "sayNameSinstall" thay thế?
Stef Heyenrath

4
Trong khi điều này hoạt động, việc phá hủy các đối số theo cách này làm cho việc theo dõi IMO trở nên khó khăn.
PW Kad

1
bạn có thể sử dụng từ khóa 'as' (theo ý kiến ​​của tôi, nó dễ đọc hơn), như {first = 'Bob', last = 'Smith'} là {first?: chuỗi; cuối cùng?: chuỗi} nhưng lý tưởng nhất là bạn nên tạo giao diện để xử lý các trường hợp này ...
Frohlich

1
Có cách nào để chuyển đối tượng tùy chọn sang chức năng khác không?
Dylanthepiguy

50

Bản in hỗ trợ các tham số mặc định ngay bây giờ:

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

Ngoài ra, việc thêm một giá trị mặc định cho phép bạn bỏ qua khai báo kiểu, bởi vì nó có thể được suy ra từ giá trị mặc định:

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

sayName('Bob');

21
Làm thế nào điều này áp dụng cho câu hỏi của OP liên quan đến giá trị mặc định cho đối tượng TypeScript được truyền dưới dạng đối số? Bạn nên hiển thị một ví dụ với một đối số đối tượng.
demisx

9
Không, nhưng tôi đã tìm thấy câu hỏi này khi tôi đang tìm cách cung cấp các tham số mặc định trong bản thảo nói chung và không có câu trả lời nào giải quyết được điều đó. Tôi cũng đã đăng phản hồi này trước khi tôi nhận thấy sự làm rõ "đối tượng" tinh tế.
bắt giữ

27

Đối tượng phá hủy đối tượng tham số là điều mà nhiều câu trả lời ở trên đang hướng tới và Typecript hiện có các phương thức để làm cho nó dễ đọc và dễ hiểu hơn bằng trực giác.

Khái niệm cơ bản về phá hủy: Bằng cách phá hủy một đối tượng, bạn có thể chọn các thuộc tính từ một đối tượng theo tên khóa. Bạn có thể xác định ít hoặc nhiều thuộc tính bạn muốn và các giá trị mặc định được đặt theo cú pháp cơ bản là let {key = default} = object.

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

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

Viết một giao diện, loại hoặc lớp cho đối tượng tham số sẽ cải thiện mức độ dễ đọc.

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
Tôi nghĩ rằng đây là câu trả lời tốt nhất cho câu hỏi!
Gezim

24

Không, TypeScript không có cách tự nhiên để đặt mặc định cho các thuộc tính của một đối tượng được xác định giống như trong đó một đối tượng có mặc định và đối tượng kia thì không. Bạn có thể định nghĩa một cấu trúc phong phú hơn:

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

    }
}

Và sử dụng nó thay cho định nghĩa loại nội tuyến.

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

Bạn không thể làm điều gì đó như thế này không may:

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

} 

Vì nó sẽ chỉ đặt mặc định nếu nameđược undefined.


Tôi nghĩ rằng đây là câu trả lời tốt nhất cho câu hỏi này và nên được đánh dấu là câu trả lời đúng.
kapad

16

Đây có thể là một cách hay để làm điều đó không liên quan đến các nhà xây dựng dài

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 mặc định được đặt ở dòng thứ hai và thứ ba, "Bob" và "Smith"
Cameron

3

Đây là một cái gì đó để thử, sử dụng giao diện và phá hủy với các giá trị mặc định. Xin lưu ý rằng "họ" là tùy chọn.

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

Không phá hủy, bạn có thể tạo một thông số mặc định và chuyển nó vào

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

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

sayName({ ...defaultName, firstName: 'Bob' })
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.