TypeScript, bir dizinin boş olup olmadığını anlayabilir ve bazı dizi metodlarının türlerini buna göre türetebilir mi?


Yakın zamanda TypeScript ve Lodash'i güncelledim ve şimdi derleyici, örneğin _.last() gibi yöntemlerin, dizi boş değilse bir değer döndüreceğini ve boşsa undefined döndüreceğini anlıyor. Bu, özellikle dizinin boş olup olmadığını bilmiyorsak, beklenen bir davranıştır.

Ancak, _.last([1,2,3]) gibi çağrılar söz konusu olduğunda, dizinin boş olmadığını biliyoruz ve bu her zaman bir sayı döndürecektir. Ayrıca, kodda dizinin boş olup olmadığını kontrol ettiğim ve buna göre hareket ettiğim birkaç yer var, örneğin:

if (!_.isEmpty(array)) {
  return _.last(array);
}

... sadece o koda bakarak, ifadenin o dizideki bir elemanın türüne sahip bir öğe döndüreceğini biliriz. Yine de dönüş türü T | undefineddir.

Böyle durumlarda değeri sadece dönüştürebileceğimi biliyorum. Ama değerleri dönüştürmekten kaçınmayı tercih ederim.

Yani benim sorum şu: Typescript'in bu tür durumları anlaması mümkün olabilir mi?

Cevap #1

Bir sistemi oluşturabiliriz, burada isEmpty dizinin tipine bilgi ekler. Bu, T değerinin true veya false olabileceği HasElements<T> adını verebileceğimiz bir tip olabilir. Tip hâlâ test edilmemişse, türünde her iki olasılığı da içermelidir (T[] & (HasElements<true> | HasElements<false>)). Ne yazık ki, bu tipe manuel olarak eklenmelidir.

import _ from 'lodash'

declare module 'lodash' {
    type HasElements<T extends boolean> = T extends boolean ? { // distributive conditional, makes HasElements<boolean> == HasElements<true> | HasElements<false>
        "gurad-traits"?: {
            hasElements?: T
        }
    }: never
    interface LoDashStatic {
        isEmpty<T extends HasElements<boolean>>(value?: T): value is T & HasElements<false>;
        last<T> (array: List<T> & HasElements<true>): T;
        last<T> (array: (List<T> & HasElements<false> )| null | undefined): undefined;
}
}

function test<T>(array: T[] & _.HasElements<boolean>, defaultValue: T): T {
    if (!_.isEmpty(array)) {
        return _.last(array);
    }else {
        let u: T = _.last(array); /// err, returns undefined
        return defaultValue;
    }
}

test([1,2,3], 1); //HasElements does not influence the assignability of arrays