简体   繁体   English

TypeScript - 如何定义同时接受数组和 object 的 function 接口

[英]TypeScript - How to define the function interface that accepts both array and object

I want to write the function that sorts both array and objects.我想编写对数组和对象进行排序的 function。 My attempt is below.我的尝试如下。

function sort(obj: any) {
    if (isArray(obj)) {
        // sort as array
    } else if (isObject(obj)) {
        // sort as object
    } else {
        // throw error that primitive value can't be sorted
    }
}

But it lost the typing at all.但它完全失去了打字。 I tried to use generic parameters but ran into the errors that obj has no array methods.我尝试使用泛型参数,但遇到了obj没有数组方法的错误。 I tried to use function overloading but ran into the impossibility to distinguish array and objects.我尝试使用 function 重载,但遇到无法区分数组和对象的问题。

Typeguards类型保护

I suppose you've seen the old link.我想你已经看到了旧链接。 There was a mistake.有一个错误。 I use sort method when obj is array当 obj 是数组时我使用排序方法

TS Playground link TS Playground 链接

Although technically, both Array.isArray and function isArray(value){ return Array.isArray(value); }虽然从技术上讲, Array.isArrayfunction isArray(value){ return Array.isArray(value); } function isArray(value){ return Array.isArray(value); } return a boolean their return types are different.返回一个function isArray(value){ return Array.isArray(value); } boolean的返回类型不同。

function isArray(value) { // returns type `boolean`
  return Array.isArray(value); // returns type `value is any[]`
}

function sort<T>(obj: T | T[]) {
    // that's why for TS this is some generic condition, like `obj.id === "42"`
    // it has no idea that `isArray` is supposed to be a typeguard.
    if (isArray(obj)) {
        // so in here it still considers `obj:T | T[]` 
        // and `T` has no `sort()` method.
        obj.sort();
    } else ...
}

same for your other "typeguard" isObject .您的其他“类型保护” isObject也是如此。

And you could alias const isArray = Array.isArray;你可以别名const isArray = Array.isArray; but basically, why?但基本上,为什么? You don't gain anything here.你在这里没有任何收获。


Sidenote, your implementation of isObject :旁注,您的isObject实现:

If you want to do if(isObject(value) || isFunction(value)) then do that, but don't "hide" the isFunction check inside something called isObject .如果你想这样做if(isObject(value) || isFunction(value))那就这样做,但不要“隐藏” isFunction检查在名为isObject的东西中。 It's you who will trip over this eventually.最终会绊倒的是 Keep these guards as stupidly simple and straightforward as possible.让这些守卫尽可能简单明了。


An example of how your code could look like TS Playground您的代码可能看起来像TS Playground的示例

const isObject = (value: unknown): value is object => typeof value === "object" && value !== null;

function sort<T extends object>(obj: T): T {
  if (Array.isArray(obj)) {
    obj.sort();

  } else if (isObject(obj)) {
    // leave me alone TS, I know what I'm doing. Things will be fine
    const unsafeObj: any = obj; 

    for (const [key, value] of Object.entries(obj).sort()) {
      delete unsafeObj[key];
      unsafeObj[key] = value;
    }
  }

  return obj;
}


const obj = sort({
  "foo": "foo",
  "bar": "bar",
  "baz": "baz",
  "asdf": "asdf"
});

console.log(obj);

Warnings: Since Array#sort() is mutating the object, I've implemented the object-sort the same way;警告:由于 Array#sort() 正在改变 object,因此我以相同的方式实现了对象排序; that doesn't make it good.这并不好。 Mutating things comes with its own set of problems.变异事物有其自身的一系列问题。

And "sorting" objects like that may be fatal to the performace of any code that has to deal with these objects.并且像这样“排序”对象可能对任何必须处理这些对象的代码的性能是致命的。 If you want ordered key-value pairs, check out Maps如果您想要有序的键值对,请查看Maps

You can specify in your function signature what are the types it's expecting:您可以在 function 签名中指定它所期望的类型:

function sort(obj: object | [])

Then you can first check if obj is an array by using the Array.isArray method.然后可以先使用 Array.isArray 方法检查 obj 是否为数组。

Array.isArray(obj)

If it returns true, you can sort it by using the Array sort method.如果返回 true,则可以使用 Array 排序方法对其进行排序。 To check whether it's an object you can do by:要检查它是否是 object,您可以执行以下操作:

typeof obj === 'object'&& !(obj instanceof Array)

If you want to sort an object you can do it using the Object.keys method which returns an array of a given object's own enumerable property and the use sort and reduce.如果要对 object 进行排序,可以使用 Object.keys 方法进行排序,该方法返回给定对象自己的可枚举属性的数组,并使用排序和归约。

For example:例如:

Object.keys(obj).sort().reduce(
   (obj, key) => { 
       obj[key] = obj[key]; 
       return obj;
    }, {}
);

You could limit your inputs and test only for array您可以限制输入并仅测试数组

function sort(input: object | []) {
    if (Array.isArray(input)) {

    } else {

    }
}

this function only accepts object or array.此 function 仅接受 object 或数组。 but problem is object is a base type and includes other types.但问题是 object 是基本类型,包括其他类型。

You can use built-in typeguards.您可以使用内置的类型保护。


type A = Array<unknown>
type B = Record<string, unknown>

const isObject = (arg: any): arg is B => !Array.isArray(arg) && arg !== null && typeof arg === 'object';

function sort(obj: any) {
    if (Array.isArray(obj)) {
        const check = obj; // A
    } else if (isObject(obj)) {
        const check = obj; //Record<string, unknown>
        // sort as object
    } else {
        const check = obj; // any
    }
}

Keep in mind, Array.isArray is already typeguard.请记住, Array.isArray已经是类型保护。

You can use unio type for obj argument:您可以将 unio 类型用于obj参数:

function sort(obj: A): A
function sort(obj: B): B
function sort(obj: A | B) {
    if (Array.isArray(obj)) {
        const check = obj; // A

        return obj
    }
    if (isObject(obj)) {
        const check = obj; //Record<string, unknown>
        // sort as object
        return obj
    }

    throw Error('Hello')

}

const x = sort([1, 2]) // A
const y = sort({ a: 1 }) // b
const z = sort(42) // error

Playground link 游乐场链接

function sorting(args: unknown){
    if(typeof args === 'object' && !Array.isArray(args)){
        // sort as if it is object
    }else{
        // sort as if it array
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM