英文:
How to create union of tuples?
问题
我正在开发一个名为Pure Terminal的库,它是用TypeScript重写的jQuery Terminal。
我有以下代码:
type Effect = 'g' | 'b' | 'i' | 'u' | 's' | 'o';
type NotEffect = `-${Effect}`;
type Item = '!' | '@';
type Effects = Array<Effect | NotEffect | Item>;
type Stack = Array<string>;
type Style = {[key: string]: string};
type Attrs = {[key: string]: string} & {style?: Style};
type Formating = [
Effects,
string,
string,
Array<string> | undefined,
string | undefined,
Attrs | undefined
];
const output: Formating = [[], '', '', undefined, undefined, undefined];
在格式化中添加undefined是为了解决具有不同长度元素的联合类型的问题,这导致了以下问题:
type Formating = [Effects, string, string]
| [Effects, string, string, Array<string>]
| [Effects, string, string, Array<string>, string]
| [Effects, string, string, Array<string>, string, Attrs]
当我想设置格式化的第4个及更多元素时,添加此类型会导致错误。添加undefined解决了TypeScript的问题,但它改变了JavaScript代码的行为。我需要添加一些hack来解决格式化中存在undefined值的问题。
有没有办法使Formating成为一个具有可变数量元素的元组?
编辑
这是我的真实代码:
const class_i = 3; // formatting中类的索引
const attrs_i = 5; // formatting中属性的索引
function get_inherit_style(stack: Stack) {
const output: Formating = [[], '', ''];
function update_attrs(value: string) {
if (!output[attrs_i]) {
output[attrs_i] = {};
}
try {
const new_attrs = JSON.parse(value);
if (new_attrs.style) {
const new_style = new_attrs.style;
const old_style = output[attrs_i].style;
output[attrs_i] = {
...new_attrs,
...output[attrs_i],
...{
style: update_style(new_style, old_style)
}
};
} else {
output[attrs_i] = {
...new_attrs,
...output[attrs_i]
};
}
} catch (e) {
warn('Invalid JSON ' + value);
}
}
if (!stack.length) {
return output;
}
for (let i = stack.length; i--;) {
let formatting = parse_formatting(stack[i]);
if (formatting.length > 5) {
const last = formatting.slice(5).join(';');
formatting = formatting.slice(0, 5).concat(last);
}
const style = formatting[0].split(/(-?[@!gbiuso])/g).filter(Boolean);
style.forEach(function(s) {
if (is_valid_effect(s) && output[0].indexOf(s) === -1) {
output[0].push(s);
}
});
for (let j = 1; j < formatting.length; ++j) {
const value = formatting[j].trim();
if (value) {
if (j === class_i) {
if (!output[class_i]) {
output[class_i] = [];
}
const classes = value.split(/\s+/);
output[class_i] = output[class_i].concat(classes);
} else if (j === attrs_i) {
update_attrs(value);
} else if (!output[j]) {
output[j] = value;
}
}
}
}
return stringify_formatting(output);
}
我遇到了一个错误:
元组类型'[Effects, string, string]'的长度为'3',在索引'3'处没有元素
当访问output[class_i]
时。
英文:
I'm working on a library Pure Terminal which is rewriting of jQuery Terminal in TypeScript.
I have this code:
type Effect = 'g' | 'b' | 'i' | 'u' | 's' | 'o';
type NotEffect = `-${Effect}`;
type Item = '!' | '@';
type Effects = Array<Effect | NotEffect | Item>;
type Stack = Array<string>;
type Style = {[key: string]: string};
type Attrs = {[key: string]: string} & {style?: Style};
type Formating = [
Effects,
string,
string,
Array<string> | undefined,
string | undefined,
Attrs | undefined
];
const output: Formating = [[], '', '', undefined, undefined, undefined];
Adding undefined to formatting was a workaround to fix the issue with Union types with different length of the elements, that was causing the issue:
type Formating = [Effects, string, string]
| [Effects, string, string, Array<string>]
| [Effects, string, string, Array<string>, string]
| [Effects, string, string, Array<string>, string, Attrs]
Adding this type gives errors when I want to set 4th and next elements of the formatting. Adding undefined solved the issue with TypeScript, but it change the behavior of JavaScript code. I need to add hacks to fix the issue that formatting has undefined values.
Is there a way to make Formating a tuple with a variable number of elements?
EDIT
This is my real code:
const class_i = 3; // index of the class in formatting
const attrs_i = 5; // index of attributes in formattings
function get_inherit_style(stack: Stack) {
const output: Formating = [[], '', ''];
function update_attrs(value: string) {
if (!output[attrs_i]) {
output[attrs_i] = {};
}
try {
const new_attrs = JSON.parse(value);
if (new_attrs.style) {
const new_style = new_attrs.style;
const old_style = output[attrs_i].style;
output[attrs_i] = {
...new_attrs,
...output[attrs_i],
...{
style: update_style(new_style, old_style)
}
};
} else {
output[attrs_i] = {
...new_attrs,
...output[attrs_i]
};
}
} catch (e) {
warn('Invalid JSON ' + value);
}
}
if (!stack.length) {
return output;
}
for (let i = stack.length; i--;) {
let formatting = parse_formatting(stack[i]);
if (formatting.length > 5) {
const last = formatting.slice(5).join(';');
formatting = formatting.slice(0, 5).concat(last);
}
const style = formatting[0].split(/(-?[@!gbiuso])/g).filter(Boolean);
style.forEach(function(s) {
if (is_valid_effect(s) && output[0].indexOf(s) === -1) {
output[0].push(s);
}
});
for (let j = 1; j < formatting.length; ++j) {
const value = formatting[j].trim();
if (value) {
if (j === class_i) {
if (!output[class_i]) {
output[class_i] = [];
}
const classes = value.split(/\s+/);
output[class_i] = output[class_i].concat(classes);
} else if (j === attrs_i) {
update_attrs(value);
} else if (!output[j]) {
output[j] = value;
}
}
}
}
return stringify_formatting(output);
}
I've got an error:
> Tuple type '[Effects, string, string]' of length '3' has no element at index '3'
When Accessing output[class_i]
答案1
得分: 2
TypeScript支持元组类型中的可选元素,可以通过在类型的末尾添加?
来表示,如果使用未标记的元组元素:
type Formatting = [Effects, string, string, Array<string>?, string?, Attrs?];
如果使用带标签的元组元素,则将?
添加到标签的末尾:
type Formatting = [a: Effects, b: string, c: string, d?: Array<string>, e?: string, f?: Attrs];
无论哪种方式,都可以允许相应的元素存在或缺失:
const output: Formatting = [[], '', '']; // 正确
const output2: Formatting = [[], '', '', ["a"], "abc"]; // 正确
英文:
TypeScript supports optional elements in tuple types which are written by adding ?
to either the end of the type if using unlabeled tuple elements:
type Formatting =
[Effects, string, string, Array<string>?, string?, Attrs?];
or to the end of the label if using labeled tuple elements:
type Formatting =
[a: Effects, b: string, c: string, d?: Array<string>, e?: string, f?: Attrs];
Either way will have the effect of allowing the corresponding elements to be present or missing:
const output: Formatting = [[], '', '']; // okay
const output2: Formatting = [[], '', '', ["a"], "abc"]; // okay
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论