올바른 유형 안전 방법으로 기록 키를 반복하려면 어떻게 해야 합니까?
몇 가지 속성에 대한 예제 레코드를 작성해 보겠습니다.
type HumanProp =
| "weight"
| "height"
| "age"
type Human = Record<HumanProp, number>;
const alice: Human = {
age: 31,
height: 176,
weight: 47
};
각 속성에 대해 사람이 읽을 수 있는 레이블도 추가합니다.
const humanPropLabels: Readonly<Record<HumanProp, string>> = {
weight: "Weight (kg)",
height: "Height (cm)",
age: "Age (full years)"
};
이제 이 레코드 유형과 정의된 레이블을 사용하여 동일한 키 유형을 가진 두 개의 레코드에 대해 반복하려고 합니다.
function describe(human: Human): string {
let lines: string[] = [];
for (const key in human) {
lines.push(`${humanPropLabels[key]}: ${human[key]}`);
}
return lines.join("\n");
}
그러나 다음 오류가 발생합니다.
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Readonly<Record<HumanProp, string>>'.
No index signature with a parameter of type 'string' was found on type 'Readonly<Record<HumanProp, string>>'.
Typescript에서 이 기능을 제대로 구현하려면 어떻게 해야 합니까?
명확하게 말하자면, 사용 여부와 관계없이 제가 찾고 있는 솔루션은Record
유형, 일반 개체, 유형, 클래스, 인터페이스 또는 기타 항목에는 다음과 같은 속성이 있어야 합니다.
새 속성을 정의하려면 한 곳에서만 정의하면 됩니다(위 HumanProp에서처럼). 반복하지 마십시오.
새 속성을 정의한 후 이 속성에 대한 새 값을 추가해야 하는 모든 위치(예: 작성 중)
alice
또는humanPropLabels
런타임 오류가 아닌 컴파일 시간에 형식 오류를 표시합니다.모든 속성에 걸쳐 반복되는 코드입니다.
describe
함수는 새 속성을 만들 때 변경되지 않은 상태로 유지됩니다.
Typescript의 유형 시스템으로 그러한 것을 구현하는 것이 가능합니까?
이를 위한 올바른 방법은 키 이름의 불변 배열을 만들고 컴파일러가 단순히 문자열 리터럴 유형을 포함하는 것이 아니라 문자열 리터럴 유형을 포함하는 것으로 인식하도록 좁은 유형을 지정하는 것이라고 생각합니다.string
이것은 주장을 통해 가장 쉽습니다.
const humanProps = ["weight", "height", "age"] as const;
// const humanProps: readonly ["weight", "height", "age"]
그런 다음 정의할 수 있습니다.HumanProp
그것의 관점에서:
type HumanProp = typeof humanProps[number];
그리고 나머지 코드는 거의 그대로 작동해야 합니다. 단, 키를 반복할 때는 위의 불변 배열을 사용해야 합니다.Object.keys()
:
type Human = Record<HumanProp, number>;
const alice: Human = {
age: 31,
height: 176,
weight: 47
};
const humanPropLabels: Readonly<Record<HumanProp, string>> = {
weight: "Weight (kg)",
height: "Height (cm)",
age: "Age (full years)"
};
function describe(human: Human): string {
let lines: string[] = [];
for (const key of humanProps) { // <-- iterate this way
lines.push(`${humanPropLabels[key]}: ${human[key]}`);
}
return lines.join("\n");
}
사용하지 않는 이유Object.keys()
컴파일러가 유형의 개체를 확인할 수 없다는 것입니다.Human
키는 에만 선언됩니다.Human
TypeScript의 개체 유형은 닫힘/정확하지 않고 열림/확장 가능합니다.이를 통해 인터페이스 확장 및 클래스 상속이 작동할 수 있습니다.
interface SuperHero extends Human {
powers: string[];
}
declare const captainStupendous: SuperHero;
describe(captainStupendous); // works, a SuperHero is a Human
당신은 원하지 않을 것입니다.describe()
당신이 지나치기 때문에 폭발하다SuperHero
특수한 유형의Human
여분으로powers
소유물.그래서 사용하는 대신Object.keys()
정확하게 생산하는 것은string[]
당신은 알려진 속성의 하드코딩된 목록을 사용해야 합니다. 코드는 다음과 같습니다.describe()
추가 속성이 있는 경우 해당 속성을 무시합니다.
그리고 요소를 추가하는 경우humanProps
describe()
변경되지 않음:
const humanProps = ["weight", "height", "age", "shoeSize"] as const; // added prop
const alice: Human = { // error!
age: 31,
height: 176,
weight: 47
};
const humanPropLabels: Readonly<Record<HumanProp, string>> = { // error!
weight: "Weight (kg)",
height: "Height (cm)",
age: "Age (full years)"
};
function describe(human: Human): string { // okay
let lines: string[] = [];
for (const key of humanProps) {
lines.push(`${humanPropLabels[key]}: ${human[key]}`);
}
return lines.join("\n");
}
좋아요, 그게 도움이 되길 바래요; 행운을 빌어요!
위의 특정 질문에 대한 좋은 답변이 제공되지만, 저의 경우, 제 실수는 애초에 레코드 유형을 사용하려고 했던 것입니다.
한 걸음 뒤로 물러서서 키를 값에 매핑하고 유형 안전한 방식으로 반복하려면 지도를 사용하는 것이 좋습니다.
type Test = 'harry' | 'sam' | 'alex';
const m = new Map<Test, number>();
for (const [k, v] of m)
{
// this won't compile because k is type Test
if (k === 'foo') { console.log(v); }
}
단점은 레코드와 달리 맵은 테스트 유형의 모든 키가 매핑되었음을 보장할 수 없다는 것입니다.하지만 저는 레코드 <숫자, 문자열>을 통해 반복하는 방법을 알아내려고 초보자로서 이 페이지에 오게 되었고, 분명히 제 실수는 애초에 레코드 유형에 도달한 것이었습니다.
어쨌든 이런 통찰력이 도움이 되었습니다.다른 사람에게 도움이 될 수도 있습니다.
유형 스크립트를 사용하려면 구부려야 하는 경우가 있습니다.다른 경우에는 Typescript를 구부리는 것이 더 나을 수 있습니다.저는 구체적인 문자열 배열 인스턴스를 유지하는 것보다 훨씬 더 간단한 것을 선택할 것입니다(인터페이스와 동기화 유지).나는 사용하지 않을 것입니다.HumanProps
에는 이 변화 ()as keyof Human
좋은 입니다. (더 읽기 쉽게 오류를 방지합니다.
function describe2(human: Human): string {
let lines: string[] = [];
for (const key in human) {
lines.push(`${humanPropLabels[key as keyof Human]}: ${human[key as keyof Human]}`);
}
return lines.join("\n");
}
언급URL : https://stackoverflow.com/questions/61829651/how-can-i-iterate-over-record-keys-in-a-proper-type-safe-way
'sourcecode' 카테고리의 다른 글
ASP.NET MVC 4 베타를 설치한 후 InvalidCastException이 느려짐 (0) | 2023.06.18 |
---|---|
Oracle 12c 설치에서 임시 위치에 액세스하지 못했습니다. (0) | 2023.06.18 |
파이썬 스크립트 실행을 중지/종료하는 방법은 무엇입니까? (0) | 2023.06.18 |
어떻게 하면 지역 소방 기지 에뮬레이터를 종료할 수 있습니까? (0) | 2023.06.18 |
옵션이 엄격하게 설정된 C# 'dynamic'에 해당하는 VB.NET (0) | 2023.06.18 |