예를 들어 다음 코드를 사용하십시오.
const [divEl, spanEl] = createElements([
['div', { id: 'test' }, [
['a', { href: 'test' }, [
['img', { src: 'test' }, null]
]],
['img', { href: 'test' }, null]
]],
['span', null, null]
]);
나는 타이프가의 유형 추론 할 divEl
수 할 수 HTMLDivElement
및 유형 spanEl
이어야합니다을 HTMLSpanElement
. 또한 주어진 속성을 확인하고 유추 된 유형에 따라 오류를 표시하기를 원합니다 (예 : 속성 이 ['img', { href: 'test' }, null]
없기 때문에에 오류를 표시해야 함 ).HTMLImageElement
href
몇 가지 조사 끝에 지금까지 내가 가진 것입니다.
type ElementTag = keyof HTMLElementTagNameMap;
type ElementAttributes<T extends ElementTag> = {
[K in keyof HTMLElementTagNameMap[T]]?: Partial<HTMLElementTagNameMap[T][K]> | null;
};
type ElementArray<T extends ElementTag> = [
T,
ElementAttributes<T> | null,
ElementArray<ElementTag>[] | string | null
];
type MappedElementArray<T> = {
[K in keyof T]: T[K] extends ElementArray<infer L> ? HTMLElementTagNameMap[L] : never;
};
// This is the signature for the createElements function.
type CreateElements = <T extends ElementArray<ElementTag>[] | []>(
array: T
) => MappedElementArray<T>;
ElementArray<ElementTag>[]
일반적인 것으로 변경 해야하지만 진행 방법을 잘 모르겠습니다.
이것이 가능할까요?
수동으로 할 수 있다는 것을 알고 있지만 T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, ...
예쁘지 않습니다.
(일부 답변)
TypeScript는 재귀 유형을 좋아하지 않습니다. 추론이 필요하지 않는 한 대부분이 문제를 해결할 수 있지만 여기에서 필요하기 때문에 TS가 마지막 단계를 수행하는 것이 가능하지 않다고 생각합니다.
다음 기능 중 하나를 사용할 수 있습니다.
첫 번째는 쉽습니다. 우리는 필요 T
에 createElements
차별 노동 조합을 연장 할 수 있습니다. 당신은 이미 이것을 가지고 있지만 이것은 그것을 보는 방법이 약간 다릅니다.
type DiscriminatedElements = {
// you can, of course, do better than unknown here.
[K in keyof HTMLElementTagNameMap]: readonly [K, Partial<HTMLElementTagNameMap[K]> | null, unknown]
}[keyof HTMLElementTagNameMap]
type ToElementTypes<T extends readonly DiscriminatedElements[]> = {
[K in keyof T]: T[K] extends [keyof HTMLElementTagNameMap, any, any] ? HTMLElementTagNameMap[T[K][0]] : never
}
declare const createElements: <T extends readonly DiscriminatedElements[] | []>(
array: T
) => ToElementTypes<T>
createElements([
['span', {}, null]
]) // [HTMLSpanElement]
두 번째는 조금 더 까다 롭습니다. 앞서 말했듯이 TS는 재귀 유형을 좋아하지 않습니다. GH # 26980을 참조하십시오 . 즉, 검사를 위해 임의의 깊이 유형을 생성하기 위해 작업 할 수 있지만이 유형을 추론과 결합하려고하면 TS는 그것이 잠재적으로 무한하다는 것을 알게 될 것입니다.
type DiscriminatedElements = {
[K in keyof HTMLElementTagNameMap]: readonly [K, Partial<HTMLElementTagNameMap[K]> | null]
}[keyof HTMLElementTagNameMap]
type NumberLine = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
type CreateElementArray<T extends readonly [any, any], N extends number> = T extends readonly [infer A, infer B] ? {
done: readonly [A, B, null],
recurse: readonly [A, B, null | readonly CreateElementArray<DiscriminatedElements, NumberLine[N]>[]]
}[N extends 0 ? 'done' : 'recurse'] : never
// Increase up N and NumberLine as required
type ElementItem = CreateElementArray<DiscriminatedElements, 4>
declare const createElements: (
array: readonly ElementItem[]
) => HTMLElement[];
const [divEl, spanEl] = createElements([
['div', { id: 'test' }, [
['a', { href: 'test' }, [
['img', { src: 'test' }, null]
]],
['img', { href: 'test' }, null] // error, as expected
]],
['span', null, null]
]);
가변 튜플이 여기서 도움이되지 않는다고 생각합니다. 그들은 언어에 대한 멋진 추가가 될 것이지만 여기서 모델링하려는 문제를 해결하지는 마십시오.
두 세계를 최대한 활용할 수있는 해결책은 HTML 요소를 튜플의 세 번째 항목으로 받아들이고 createElements
해당 배열 내에서 간단히 호출 하는 것입니다.
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다