Javascript 混合类型的数组,但在数组中具有特定类型的最小计数

Javascript 混合类型的数组,但在数组中具有特定类型的最小计数,javascript,arrays,typescript,Javascript,Arrays,Typescript,假设我想对给定数组强制执行严格的类型输入,这样: 它可以包含number 它必须包含一个或多个字符串 …并且数组中number和string的顺序无关紧要,因此以下数组是有效的: ['foo',1,2,3] [1,2,'foo',3] ['foo'] 但以下数组无效: [1,2,3](因为它在数组中至少需要一个字符串) 最接近我的解决方案是将类型定义为: /** * Array must contain: * - One or more string * - Zero or m

假设我想对给定数组强制执行严格的类型输入,这样:

  • 它可以包含
    number
  • 它必须包含一个或多个
    字符串
…并且数组中
number
string
的顺序无关紧要,因此以下数组是有效的:

  • ['foo',1,2,3]
  • [1,2,'foo',3]
  • ['foo']
但以下数组无效:

  • [1,2,3]
    (因为它在数组中至少需要一个
    字符串)
最接近我的解决方案是将类型定义为:

/**
 * Array must contain:
 * - One or more string
 * - Zero or more numbers
 * @type
 */
type CustomArray = [string] & Array<number | string>

const a: CustomArray = ['foo', 1, 2, 3]; // Should pass (works as expected)
const b: CustomArray = [1, 2, 'foo', 3]; // Should pass (but doesn't with my code)
const c: CustomArray = ['string'];       // Should pass (works as expected)
const d: CustomArray = [1, 2, 3];        // Should fail (works as expected)
/**
*数组必须包含:
*-一个或多个字符串
*-零个或多个数字
*@type
*/
键入CustomArray=[string]&数组
常量a:CustomArray=[foo',1,2,3];//应通过(按预期工作)
常量b:CustomArray=[1,2,'foo',3];//应该通过(但与我的代码不一致)
常量c:CustomArray=['string'];//应通过(按预期工作)
常量d:CustomArray=[1,2,3];//应失败(按预期工作)

但这意味着数组的第一个元素必须是字符串,而不是在整个数组中强制执行最小计数1

无法告诉TypeScript数组应该至少包含一个特定类型的元素

您只能创建一个数字/字符串数组:

type CustomArray = (number | string)[];

类型CustomArray=Array;
然后在向数组添加数据或从数组中读取数据的位置添加数据。

这是个好主意吗

/**
*数组必须包含:
*-一个或多个字符串
*-零个或多个数字
*@type
*/
console.clear();
常量CustomArray=(arr:Array)=>{
如果(!arr.length){
返回新的TypeError(“无效:数组应至少包含一个元素”);
}
const oneString=arr.filter(v=>v.constructor==String);
const errowtypes=arr.filter(v=>v.constructor!==Number&&v.constructor!==String);
如果(错误类型){
返回新类型错误(`Invalid:[${JSON.stringify(arr)}]包含无效类型`);
}
如果(!oneString){
返回新的TypeError(`Invalid:[${JSON.stringify(arr)}]应至少包含一个字符串值`);
}
返回arr;
};
类型MyArray=Array |类型错误;
常量a:MyArray=CustomArray(['foo',1,2,3]);//应通过(按预期工作)
常量b:MyArray=CustomArray([1,2,'foo',3]);//应通过(按预期工作)
常量c:MyArray=CustomArray(['string']);//应通过(按预期工作)
常量d:MyArray=CustomArray([1,2,3]);//应失败(按预期工作)
常量日志=(v:any)=>
log(v instanceof TypeError?v.message:JSON.stringify(v));
日志(a);
日志(b);
对数(c);

对数(d)对于具有特定类型的最小大小的数组,似乎无法进行编译时检查


以下是基于运行时检查的解决方案:

我将引入字符串和数字的元组,而不是使用不同类型的数组

type Custom = [number[], string[]];
然后,您可以定义一个检查函数,查看它是否满足您的要求:

const isValid = (c: Custom): boolean => {
    const [_, strings] = c;

    return strings.length >= 1;
};
如果需要将输入作为数组,可以将其转换为元组:

const toCustom = (a: (string | number)[]): Custom => {
    const numbers: number[] = [];
    const strings: string[] = [];

    a.forEach((element) => {
        if (typeof element === "string") {
            strings.push(element);
        } else if (typeof element === "number") {
            numbers.push(element);
        } else {
            throw new Error("Unexpected type given"); // for runtime errors
        }
    });

    return [
        numbers,
        strings
    ];
}
然后您可以强制执行运行时检查:

const a = isValid(toCustom([
    "foo",
    1,
    2,
    3
])); // Should pass
const b = isValid(toCustom([
    1,
    2,
    "foo",
    3
])); // Should pass

const c = isValid(toCustom(["string"]));       // Should pass 
const d = isValid(toCustom([
    1,
    2,
    3
])); // should fail

console.log(a, b, c, d); // prints: true true true false

可能有一种方法可以强制设置数组的最小大小,但它只适用于元组方法:

type OneOrMore<T> = {
    0: T
} & T[]
type Custom = [number[], OneOrMore<string>];

const bar: Custom = [
    [
        1,
        2,
        3
    ],
    ["bar"],
];

const foo: Custom = [
    [
        1,
        2,
        3
    ],
    [], // missing zero property
];
键入一个或多个={
0:T
}&T[]
键入Custom=[number[],一个或多个];
常量栏:自定义=[
[
1.
2.
3.
],
[“酒吧],
];
常量foo:自定义=[
[
1.
2.
3.
],
[],//缺少零属性
];

使用定制型防护装置是否可行?相关:添加一个
和{u isCustomArray:true}
,然后用复选框进行类型转换。@Jonaswillms:这将如何验证至少有一个字符串项的要求?
函数asCustomArray(array:(string | number)[]):CustomArray | never{…
。。。。或者只是使用自定义类型保护?…虽然这不会在运行前进行严格的类型检查。那么为什么不使用
CustomArray
而不是
MyArray
arr as MyArray
就有意义了。还返回一个错误真的很难看谢谢你的回答!然而,我并不是在寻找一个进行这种检查的函数:只是一个满足需求的类型定义。看来现在不可能了。@Terry,没问题。我必须承认,我很少觉得有必要使用打字稿。谢谢你的回答!然而,我并不是在寻找一个进行这种检查的函数:只是一个满足需求的类型定义。看来现在不可能了。
type OneOrMore<T> = {
    0: T
} & T[]
type Custom = [number[], OneOrMore<string>];

const bar: Custom = [
    [
        1,
        2,
        3
    ],
    ["bar"],
];

const foo: Custom = [
    [
        1,
        2,
        3
    ],
    [], // missing zero property
];