如何创建元组的并集?

huangapple go评论72阅读模式
英文:

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 = &#39;g&#39; | &#39;b&#39; | &#39;i&#39; | &#39;u&#39; | &#39;s&#39; | &#39;o&#39;;
type NotEffect = `-${Effect}`;
type Item = &#39;!&#39; | &#39;@&#39;;
type Effects = Array&lt;Effect | NotEffect | Item&gt;;
type Stack = Array&lt;string&gt;;

type Style = {[key: string]: string};
type Attrs = {[key: string]: string} &amp; {style?: Style};

type Formating = [
    Effects,
    string,
    string,
    Array&lt;string&gt; | undefined,
    string | undefined,
    Attrs | undefined
];

const output: Formating = [[], &#39;&#39;, &#39;&#39;, 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&lt;string&gt;]
  | [Effects, string, string, Array&lt;string&gt;, string]
  | [Effects, string, string, Array&lt;string&gt;, 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 = [[], &#39;&#39;, &#39;&#39;];
    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(&#39;Invalid JSON &#39; + value);
        }
    }

    if (!stack.length) {
        return output;
    }
    for (let i = stack.length; i--;) {
        let formatting = parse_formatting(stack[i]);
        if (formatting.length &gt; 5) {
            const last = formatting.slice(5).join(&#39;;&#39;);
            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) &amp;&amp; output[0].indexOf(s) === -1) {
                output[0].push(s);
            }
        });
        for (let j = 1; j &lt; 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"]; // 正确

代码的 Playground 链接

英文:

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&lt;string&gt;?, string?, Attrs?];

or to the end of the label if using labeled tuple elements:

type Formatting = 
[a: Effects, b: string, c: string, d?: Array&lt;string&gt;, e?: string, f?: Attrs];

Either way will have the effect of allowing the corresponding elements to be present or missing:

const output: Formatting = [[], &#39;&#39;, &#39;&#39;]; // okay
const output2: Formatting = [[], &#39;&#39;, &#39;&#39;, [&quot;a&quot;], &quot;abc&quot;]; // okay

Playground link to code

huangapple
  • 本文由 发表于 2023年8月9日 04:34:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/76863045.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定