typescript - Hata: 'number | undefined' türü 'number | { valueOf(): number; }' türüne atanamaz mı?


Elimde bu dizi türü var:

interface Details {
  Name: string;
  URL: string;
  Year: number;
}
interface AppState {
  data: Details[];
}

Bir x ekseni oluşturmak için D3 kullanıyorum, bu şekilde:

 createChart = () => {
    const { data } = this.state;
    const width = 900,
      height = 600;

    // x-axis
    const x = d3
      .scaleLinear()
      .domain([
        d3.min(data, ({ Year }) => (Year ? Year - 1 : 0)), // ERROR
        d3.max(data, ({ Year }) => (Year ? Year + 1 : 0)) // ERROR
      ])
      .range([0, width]);
  };

İşaretli satırlarda d3.min ve d3.max kullanırken aşağıdaki hatayı alıyorum:

Type 'number | undefined', type 'number | { valueOf(): number; }' türüne atanamaz. Type 'undefined', type 'number | { valueOf(): number; }' türüne atanamaz.

Bunu nasıl çalıştırabilirim?

Cevap #1

Sizin d3.min() çağrınız için derleyici aşağıdaki tür tanımını kullanacaktır:

export function min<T, U extends Numeric>(array: Iterable<T>, accessor: (datum: T, index: number, array: Iterable<T>) => U | undefined | null): U | undefined;

Gördüğünüz gibi, fonksiyon ya U döndürebilir—sizin durumunuzda Details.Year türü, yani number—ya da undefined. Ancak bu, sadece sayılardan veya sayılara dönüştürülebilecek değerlerden oluşan bir dizi alan .domain() yönteminin tür tanımıyla eşleşmez:

domain(domain: Array<number | { valueOf(): number }>): this;

Bu, neden hata aldığınızı açıklar. Aynı şekilde, d3.max() için de geçerlidir.

Belgelere bakıldığında, d3.min()'in undefined döndürmesinin nedenleri oldukça sınırlıdır:

Eğer yinelenebilir nesne karşılaştırılabilir değerler içermiyorsa, tanımsız döner.

Verilen kodunuzla bu sorunla karşılaşmayacağınız garanti edilir. Bu nedenle d3.min() ve d3.max() dönüş değerlerini güvenle number olarak dönüştürebilirsiniz:

const x = d3
  .scaleLinear()
  .domain([
    d3.min(data, ({ Year }) => (Year ? Year - 1 : 0)) as number,  // cast to number
    d3.max(data, ({ Year }) => (Year ? Year + 1 : 0)) as number   // cast to number
  ])
  .range([0, width]);

İlgili makaleler