This is similar to extract property values from array but I also need to strict the type of array.
Take the following code as example:
type ElemProp = {id: number, name: string, quickFormat?: boolean }
const formatList:ElemProp[] = [
{id:1, name: 'ABC'},
{id: 3, name: 'XYZ'},
{id: 98, name: 'GOGOGO', quickFormat: true}
] as const
type IdEnum = (typeof formatList)[number]['id']
The IdEnum
is evaluated as number
instead of 1|3|98
.
Nonetheless, removing :ElemProp[]
will give the enum, but now I lose all type support.
The question is: how to obtain the enum while keeping type support for the original array?
I tried changing things to readonly, adding as const but as long as the ElemProp[]
is there, IdEnum
returns number
.
Post-answer update:
This is the original intent: I was trying to limit the type of paragraph styles supplied to paragraphs when using https://github.com/dolanmiu/docx/ to create docx files in NodeJS. This is not very elegant at the moment but I'm seeing where this is going.
import dx from 'docx';
import { IPropertiesOptions } from 'docx/build/file/core-properties';
type StylesAndNumberings = Required<Pick<IPropertiesOptions, 'styles' | 'numbering'>>; // for reference only
export type ExtractParagraphIds<U extends Partial<IPropertiesOptions>> = U extends {
readonly styles: { readonly paragraphStyles: infer U extends readonly { id: string }[] };
}
? U[number]['id']
: never;
const docProps = {
styles: {
paragraphStyles: [
{
id: 'normal',
name: 'Normal',
basedOn: 'Normal',
next: 'Normal',
quickFormat: true,
run: {
font: 'Arial',
size: 22,
},
}]
}
} as const satisfies Partial<IPropertiesOptions>;
type IdEnum = ExtractParagraphIds<typeof docProps>;
export const textToParagraph = <T extends Partial<IPropertiesOptions>>(
t: string,
runFormat: dx.IRunOptions = {},
paragraphOptions: dx.IParagraphOptions & { style?: ExtractParagraphIds<T> } = {},
paragraphFreeChildren: dx.IParagraphOptions['children'] = []
) => {
const text = t.split('\n');
if (text.length === 1) {
return new dx.Paragraph({
wordWrap: true,
children: [
new dx.TextRun({
text: t,
...runFormat,
}),
...paragraphFreeChildren,
],
...paragraphOptions,
});
}
return new dx.Paragraph({
children: [
...text.map((line, i) => {
return new dx.TextRun({
text: line,
...runFormat,
break: i ? 1 : 0,
});
}),
...paragraphFreeChildren,
],
...paragraphOptions,
});
};
Use satisfies
:
type ElemProp = {id: number, name: string, quickFormat?: boolean }
const formatList = [
{id:1, name: 'ABC'},
{id: 3, name: 'XYZ'},
{id: 98, name: 'GOGOGO', quickFormat: true}
] as const satisfies ElemProp[];
type IdEnum = (typeof formatList)[number]['id']