Tìm kiếm trang web

javascript - Sử dụng "as const" trong Typescript mà không thêm các sửa đổi "readonly"?


Tôi đang tìm một cách dễ dàng để nhận được kiểu đúng cho các hằng số. Ví dụ:

const arr = [{ a: 1 }];
// actual type: { a: number }[]
// desired type: [{ a: 1 }]

Nó kiểu như hoạt động nếu tôi sử dụng as const trên toàn bộ, nhưng nó sẽ thêm readonly:

const arr = [{ a: 1 }] as const;
// readonly [{ readonly a: 1 }]

Tôi không muốn readonly vì tôi sẽ nhận được rất nhiều Kiểu 'readonly ...' là 'readonly' và không thể gán cho kiểu có thể thay đổi '...'.

Tôi đã thử định nghĩa một generic "Mutable":

type Mutable<T> = {
  -readonly [K in keyof T]: Mutable<T[K]>;
}

type Arr = Mutable<typeof arr>;

// [Mutable<{ readonly a: 1 }>]

Tuy nhiên, TS không áp dụng Mutable theo đệ quy trong xem trước kiểu của VS Code. Tôi không nghĩ rằng VS Code có thể đánh giá đệ quy Mutable, vì nó có thể quá chậm.

Có cách nào tốt hơn để làm một thứ gì đó giống như as const, nhưng không thêm readonly không?

Câu trả lời #1

Sử dụng satisfies kết hợp với as const

// To get a mutable array/object type
const arr = [
    {a: 1} satisfies Record<string, number>,
] as const satisfies Record<string, number>[];
type Arr = typeof arr;

const arrTest1: [{a: number}] = arr;

// To get a mutable tuple type
const tuple = ['a', 'b'] as const satisfies string[];
type Tuple = typeof tuple[number];

const tupleTest1: ('a' | 'b')[] = tuple;

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

Câu trả lời #2

Thực ra, bạn đã làm cho mảng này có thể thay đổi. Nhưng có lẽ bạn đã nhận thấy rằng kiểu của phần tử đầu tiên là {a: 1}

const arr = [{ a: 1 }] as const;

type Mutable<T> = {
    -readonly [K in keyof T]:  Mutable<T[K]>;
}

type Arr = Mutable<typeof arr>[0]; // {a: 1}

Bởi vì a có kiểu literal number 1, bạn vẫn không thể thay đổi phần tử đó.

Xin lỗi, bạn có thể, nhưng bạn chỉ được phép sử dụng 1

const x: Arr = [{ a: 1 }]
x[0].a = 1 // ok

Để làm cho nó có thể thay đổi hoàn toàn, bạn nên ánh xạ tất cả các kiểu literal sang các kiểu phổ biến hơn.

1 -> số

type LiteralToCommon<T extends PropertyKey> =
    T extends number
    ? number : T extends string
    ? string : T extends symbol
    ? symbol : never;

type Mutable<T> = {
    -readonly [K in keyof T]: T[K] extends PropertyKey ? LiteralToCommon<T[K]> : Mutable<T[K]>;
}

const arr = [{ a: 1 }] as const;


type Arr = Mutable<typeof arr>;

const x: Arr = [{ a: 1 }]

x[0].a = 10 // ok

Sân chơi

Có một cách thay thế:

type Mutable<T> = {
    -readonly [K in keyof T]: Mutable<T[K]>;
}

const arr = [{ a: 1 }];

type ImmutableArr = Readonly<typeof arr>

type MutableArr = Mutable<ImmutableArr>

type Arr = Mutable<typeof arr>;

const x: MutableArr = [{ a: 1 }]

x[0].a = 10 // ok

Bạn có thể chỉ sử dụng Readonly cho mảng. Tiện ích này sẽ suy ra {a: 1} thành {a: number}

Bài viết liên quan