This is similar to extract property values from array, however, in this case, the type of array needs to be restricted as well.
Consider the following 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
value is determined as number
instead of 1|3|98
.
However, removing :ElemProp[]
would result in getting the enum, but it will lead to losing all type support.
The question arises: how can one obtain the enum while still maintaining type support for the original array?
Attempts have been made to change things to readonly, add as const, yet as long as the ElemProp[]
remains, IdEnum
continues to return number
.
Post-answer update:
The main goal here was to restrict the types of paragraph styles provided to paragraphs when utilizing https://github.com/dolanmiu/docx/ for creating docx files in NodeJS. Although it may not seem very refined at present, there are insights into its potential growth.
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,
});
};