Bản thảo: loại kết hợp xuất phát từ mảng các đối tượng


8

Tôi muốn khai báo một mảng các mặt hàng được thi hành theo kiểu và có thể lấy được một loại kết hợp từ nó. Mẫu này hoạt động nếu bạn không cung cấp một loại rõ ràng cho các mục trong mảng. Tôi không chắc làm thế nào để giải thích tốt nhất vì vậy đây là một ví dụ:

VÍ DỤ 1

type Pair = {
  key: string;
  value: number;
};

const pairs: ReadonlyArray<Pair> = [
  { key: 'foo', value: 1 },
  { key: 'bar', value: 2 },
] as const;

type Keys = typeof pairs[number]['key']

VÍ DỤ 2

type Data = {
  name: string;
  age: number;
};

const DataRecord: Record<string, Data> = {
  foo: { name: 'Mark', age: 35 },
  bar: { name: 'Jeff', age: 56 },
} as const;

type Keys = keyof typeof DataRecord;

Dưới đây là một ví dụ về việc lấy các phím khi sử dụng as const. Tôi muốn hành vi tương tự nhưng với mảng được gõ rõ ràng.

const pairs = [
  { key: 'foo', value: 1 },
  { key: 'bar', value: 2 },
] as const;

type Keys = typeof pairs[number]['key']; // "foo" | "bar"

giá trị mong muốn của khóa: "foo"|"bar"

giá trị thực của các khóa: string


4
Tôi không nghĩ rằng bạn có thể thực hiện việc này một cách linh hoạt theo cách bạn đang cố gắng, bạn đang kết hợp các giá trị thời gian chạy với các kiểu thời gian biên dịch. Bạn sẽ phải cung cấp keythuộc tính của Pairloại bạn muốn, sau đó nó sẽ hoạt động như bạn đã viết.
Jared Smith

4
Điều này có trả lời câu hỏi của bạn không? Kiểu đánh máy dẫn xuất kiểu kết hợp từ các giá trị tuple / mảng
cha mẹ

@JaredSmith đây không phải là một vấn đề trong thời gian chạy. Tôi đang sử dụng điều này để khai báo một số giá trị tùy ý không thay đổi trong khi thực hiện. Điều này sẽ tương đương với khóa cài đặt: "foo" | "bar" trong khai báo kiểu.
Bến

"đây không phải là một vấn đề trong thời gian chạy" --- bản thảo không có thời gian chạy, vì vậy đây một vấn đề phải làm trong thời gian chạy.
zerkms

1
@Ben cho phép tôi cụ thể hơn: Tôi không nghĩ bạn có thể làm điều này với một bộ các thuộc tính được rút ra khỏi các loại tham chiếu có thể thay đổi theo cách bạn có thể với một bộ nguyên thủy bất biến. Bạn có thể nói possibleKeys = ['foo', 'bar'] as const; type Keys = typeof possibleKeys[number]; type Pair = { key: Keys, value: number };nhưng bạn vẫn cần liệt kê rõ ràng các phím có thể.
Jared Smith

Câu trả lời:


3

Đối với một biến, bạn có thể để trình biên dịch suy ra kiểu từ khởi tạo hoặc viết nó ra một cách rõ ràng. Nếu bạn viết nó một cách rõ ràng, như bạn có, thì giá trị khởi tạo được kiểm tra theo chú thích, nhưng loại thực tế của trình khởi tạo không ảnh hưởng đến loại biến (vì vậy bạn mất thông tin loại bạn muốn). Nếu bạn để trình biên dịch suy ra nó, bạn không còn có thể hạn chế loại để phù hợp với một giao diện cụ thể (như bạn muốn)

Giải pháp cho việc này là sử dụng một hàm chung để hạn chế giá trị và suy ra loại thực tế của nó:

type Pair = {
  key: string;
  value: number;
};
function craetePairsArray<T extends readonly Pair[] & Array<{key: V}>, V extends string>(...args: T) {
    return args
}

const pairs = craetePairsArray(
  { key: 'foo', value: 1 },
  { key: 'bar', value: 2 },
)

type Keys1 = typeof pairs[number]['key']

type Data = {
  name: string;
  age: number;
};

function craeteDataObject<T extends Record<string, Data>>(arg: T) {
    return arg;
}
const DataRecord = craeteDataObject({
  foo: { name: 'Mark', age: 35 },
  bar: { name: 'Jeff', age: 56 },
})

type Keys2 = keyof typeof DataRecord;

Liên kết sân chơi

Lưu ý: Đối với trường hợp mảng, chúng ta cần mạnh tay trình biên dịch một chút để suy ra các kiểu chữ chuỗi cho key, do đó, toàn bộ & Array<{key: V}>, trong đó Vmột tham số kiểu mở rộngstring


1
Cảm ơn bạn! Đây chính xác là những gì tôi cần!
Bến

2

Các cách tiếp cận thông thường là:

  • hãy để TS suy ra loại pairsbằng cách bỏ qua loại rõ ràng ReadonlyArray<Pair>(xem câu trả lời )
  • cho keyvào Pairloại"foo"|"bar"

Nếu bạn không muốn làm điều này, thì cách duy nhất để suy ra các khóa của bạn hạn chế loại pairslà sử dụng chức năng trợ giúp. Các Pairloại cũng sẽ được thực hiện chung để tiết kiệm cho keychuỗi các loại chữ. Bạn có thể sử dụng IIFE để thực hiện bài tập nhỏ gọn:

type Pair<K = string> = {
    key: K;
    value: number;
};

const pairs = (<T>(p: readonly Pair<T>[]) => p)([
    { key: 'foo', value: 1 },
    { key: 'bar', value: 2 },
] as const) // readonly Pair<"foo" | "bar">[]

type Keys = typeof pairs[number]['key'] // "foo" | "bar"

Sân chơi

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.