Varför kan inte { loading: { a: false } } tilldelas till en parameter av typen Partial<Factory<T>> i TypeScript?


Jag har följande TypeScript-kod:

type Factory<T> = T & {
  loading: {
    [K: string]: boolean
  }
}

function factoryInitState<T>(initState: T) {
  const setFn = (state: Partial<Factory<T>>) => {}

// Argument of type '{ loading: { a: false; }; }' is not assignable to parameter of type 'Partial<Factory<T>>'.
  setFn({
    loading: {
      a: false,
    },
  })
}

Kan någon förklara varför detta fel uppstår och hur man åtgärdar det.

Här är förslaget från GPT,

type Factory<T> = {
  [K in keyof T]: T[K]
} & {
  loading: {
    [K: string]: boolean
  }
}
function factoryInitState<T>(initState: T) {
  const setFn = (state: Partial<Factory<T>>) => {}
  setFn({
    loading: {
      a: false,
    },
  } as unknown as Partial<Factory<T>>)
}

factoryInitState({})

Men det är inte elegant

Svar #1

Du måste sprida initState på Factory<T> för att uppfylla T-gränsen själv:

type Factory<T> = T & {
  loading: {
    [K: string]: boolean
  }
}

function factoryInitState<T>(initState: T) {
  const setFn = (state: Partial<Factory<T>>) => {}

// Argument of type '{ loading: { a: false; }; }' is not assignable to parameter of type 'Partial<Factory<T>>'.
  setFn({
    ...initState,
    loading: {
      a: false,
    },
  })
}

Svar #2

Jag tror att detta är en begränsning i kompilatorn, även om jag inte kan precis peka ut det (troligtvis beroende på hur Partial är definierad).

Så länge den generiska T är okänd, kommer Partial<T> (eller, i ditt fall, Partial<Factory<T>>) inte vara kompatibel med ett objekt som inte har några kända egenskaper gemensamma med T (det vill fortfarande veta vilka dessa egenskaper är).

Det finns dock ett enkelt sätt att kringgå det:

type Factory<T> = T & {
  loading: {
    [K: string]: boolean
  }
}

function factoryInitState<T>(initState: T) {
  const setFn = (state: Partial<Factory<T>>) => {}

  setFn({
    ...({} as T),
    loading: {
      a: false,
    },
  })
}