Cú pháp cho các hàm mũi tên typecript với generic là gì?


192

Sổ tay bản thảo hiện không có gì trên các hàm mũi tên. Các hàm thông thường có thể được gõ chung với cú pháp này: ví dụ:

function identity<T>(arg: T): T {
    return arg;
}

Cú pháp cho các chức năng mũi tên là gì?

Câu trả lời:


228

Ví dụ đầy đủ giải thích cú pháp được tham chiếu bởi Robin ... đã mang nó về nhà cho tôi:

Hàm chung

Một cái gì đó như sau hoạt động tốt:

function foo<T>(x: T): T { return x; }

Tuy nhiên, sử dụng một hàm mũi tên chung sẽ không:

const foo = <T>(x: T) => x; // ERROR : unclosed `T` tag

Giải pháp thay thế: Sử dụng mở rộng trên tham số chung để gợi ý trình biên dịch rằng đó là chung, ví dụ:

const foo = <T extends unknown>(x: T) => x;

1
có thể khai báo một số loại chung được xác định trước cho const foo? tức là type GenericFun<T, A=T> = (payload: A) => T;làm cho const foo: GenericFunvẫn chung chung mà không cung cấp một Tloại?
ciekawy

@ciekawy, AFAIK, không phải vậy, và tôi nghĩ điều đó có ý nghĩa. Generics là về việc cho phép các loại thứ tự cao hơn trong một ý nghĩa. GenericFun<T, A=T>định nghĩa một tập hợp bao gồm các loại khác GenericFun<number>GenericFun<string>trong số các loại khác. Cho phép các loại chung chung tạo thành một chú thích loại trực tiếp - ví dụ: const const foo: GenericFun- tuy nhiên, sẽ có xu hướng làm xói mòn an toàn tĩnh được cung cấp bằng cách yêu cầu tính đặc hiệu, ví dụ: const foo: GenericFun<string>hoặcconst foo: GenericFun<number>
jbmilgrom

7
Ví dụ thứ hai của bạn chỉ là một lỗi trong một .tsxtệp (TypeScript + JSX). Trong một .tstệp, nó hoạt động tốt, như bạn có thể thấy trên sân chơi TypeScript .
danvk

46
Các trình biên dịch bản thảo mới hơn cũng hỗ trợ dấu phẩy const foo = <T,>(x: T) => x;để vượt qua sự mơ hồ của JSX.
Thomas

1
@danvk Đáng lưu ý rằng điều này chỉ đúng với những người đã cấm JSX trong các tệp TS - nếu một dự án được định cấu hình để cho phép JSX trong các tệp TS, bạn vẫn sẽ cần "kéo dài" hoặc dấu phẩy kéo dài
Matt

63

Tôi tìm thấy ví dụ trên khó hiểu. Tôi đang sử dụng React và JSX vì vậy tôi nghĩ nó phức tạp hóa kịch bản.

Tôi đã làm rõ từ TypeScript Deep Dive , trong đó nêu rõ về tướng mũi tên:

Giải pháp thay thế: Sử dụng mở rộng trên tham số chung để gợi ý trình biên dịch rằng đó là chung, điều này xuất phát từ một ví dụ đơn giản giúp tôi.

    const identity = < T extends {} >(arg: T): T => { return arg; }

8
"T kéo dài bất kỳ" sau đó sẽ hỗ trợ void.
Mohamed Fakhreddine

48

Nếu bạn đang ở trong một .tsxtệp bạn không thể chỉ viết <T>, nhưng điều này hoạt động:

const foo = <T, >(x: T) => x;

Trái ngược với vụ extends {}hack, vụ hack này ít nhất bảo tồn ý định.


Họ có kế hoạch để sửa chữa hành vi này?
Alexander Kim

Tôi đoán không có nhiều điều có thể được thực hiện về điều này ... các cú pháp chung của JSX và Bản mô tả chỉ đụng độ ở đây ..
mb21

1
Tuyệt vời - đây là câu trả lời tốt nhất: hoạt động hoàn hảo và không làm thay đổi hành vi nào cả!
Geoff Davids

Những gì về loại tham số mặc định? const foo = <T = any,>(x: T) => xkhông hoạt động ...
Mikhail Vasin

34

Đặc tả ngôn ngữ nói trên p.64f

Cấu trúc có dạng <T> (...) => {...} có thể được phân tích cú pháp dưới dạng biểu thức hàm mũi tên với tham số loại hoặc xác nhận loại được áp dụng cho hàm mũi tên không có tham số loại. Nó được giải quyết như trước đây [..]

thí dụ:

// helper function needed because Backbone-couchdb's sync does not return a jqxhr
let fetched = <
           R extends Backbone.Collection<any> >(c:R) => {
               return new Promise(function (fulfill, reject) {
                   c.fetch({reset: true, success: fulfill, error: reject})
               });
           };


3

trong khi câu trả lời phổ biến với extends {}các tác phẩm và tốt hơn là extends any, nó buộc Tphải là một đối tượng

const foo = <T extends {}>(x: T) => x;

để tránh điều này và bảo vệ an toàn loại, extends unknownthay vào đó bạn có thể sử dụng

const foo = <T extends unknown>(x: T) => x;

1

Tôi sử dụng loại khai báo này:

const identity: { <T>(arg: T): T } = (arg) => arg;

Nó cho phép xác định các đạo cụ bổ sung cho chức năng của bạn nếu bạn cần và trong một số trường hợp, nó giúp giữ cho thân chức năng sạch hơn khỏi định nghĩa chung.

Nếu bạn không cần các đạo cụ bổ sung (sắp xếp không gian tên của sự vật), nó có thể được đơn giản hóa thành:

const identity: <T>(arg: T) => T = (arg) => arg;

1

quá muộn, nhưng với ES6 không cần gia hạn thì nó vẫn hoạt động với tôi .... :)

let getArray = <T>(items: T[]): T[] => {
    return new Array<T>().concat(items)
}

let myNumArr = getArray<number>([100, 200, 300]);
let myStrArr = getArray<string>(["Hello", "World"]);
myNumArr.push(1)
console.log(myNumArr)

Điều này không làm việc cho tôi, tôi phải thêm một dấu phẩy như vậy : <T, >. như mô tả trong @Thomas comment dưới @jbmilgrom' câu trả lời
apollo

Bạn nên đọc các giải pháp khác trước khi đăng. Giải pháp của bạn đã được đăng với lời giải thích. Nó chỉ hoạt động bên trong tệp .ts, không phải tệp .tsx.
Isaac Pak
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.