Тип Generi c с указанием c ключа и значения - PullRequest
0 голосов
/ 17 марта 2020

Я работаю над функцией, которая принимает два универсальных параметра типа c. Один из них - тип Object, а другой - строка keyof переданного типа объекта. Мне нужно как-то определить, что при условии, что Object должен содержать ключ, предоставленный во втором параметре, и его значение также должно быть указанного типа.

Я пробовал что-то вроде этого:

const someFn = <
  T extends {[key: string]: number | null},
  K extends keyof T
>(data: T[], dataField: K) => {

  // expecting data values to be (number | null)[] for further purposes
  const dataValues = data.map(datum => datum[dataField]);

}

Однако приведенный выше код работает, только если все ключи в переданном объекте number | null

type WorkingType = { value: number | null }
const workingArray = [{value: 1}, {value: null}]

someFn<WorkingType, "value">(workingArray, "value") // this works just fine

, но если объект, содержащий поле другого типа, я получил ошибку:

type FailingType = { value: number | null, sthElse: string }
const workingArray = [{value: 1, sthElse: ""}, {value: null, sthElse}]

//. Property 'sthElse' is incompatible with index signature.
//   Type 'string' is not assignable to type 'number | null'
someFn<FailingType, "value">(workingArray, "value") 

, так что мне нужно Для этого нужно каким-то образом предоставить информацию о том, что только ключ, указанный как K, должен быть number | null Я пробовал что-то вроде:

const someFn<
  T extends { [key: T]: number | null },
  K extends keyof T
>(data: T[], dataKey: K) => {/* ... */}

Но это, похоже, не разрешено TS, я получил An index signature parameter type must be either 'string' or 'number'. Есть ли какой-нибудь возможный способ достичь моей цели?

1 Ответ

0 голосов
/ 17 марта 2020

Я надеюсь, что вы поняли, в любом случае, это работает для меня:

    interface someFnI {
    <T,K extends keyof T>(data: T[], dataField: K);
}



const someFn = <
    T,
    K extends keyof T
>(data: T[], dataField: K) => {

    // expecting data values to be (number | null)[] for further purposes
const dataValues: T[K][] = data.map(datum => {
    return datum[dataField]});
    console.log(dataValues);

}

let myIdentity: someFnI = someFn;


type NotFailingType = { value: number | null, sthElse: string }
const workingArray = [
    { value: 1, sthElse: "" }, 
    { value: null, sthElse: null },
    //this will break as expected : uncomment below to check
    // { value: "notallowed", sthElse: null }
]

//. Property 'sthElse' is incompatible with index signature.
//   Type 'string' is not assignable to type 'number | null'
myIdentity<NotFailingType, "value">(workingArray, "value")



type WorkingType = { value: number | null }
const workingArray2 = [{ value: 1 }, { value: null }]

myIdentity<WorkingType, "value">(workingArray2, "value")
...