簡體   English   中英

如何在 TypeScript 中定義通用字段副本 function

[英]How to define a generic field copy function in TypeScript

我正在嘗試在 TypeScript 中定義通用字段副本 function 但未能使打字正常工作。 請參見下面代碼中的方法 4。 我的問題是,我如何編寫一個 function 可以使 TypeScript 打字正常工作並檢查目標類型和源類型?

長話短說:我正在從事一個從 NoSQL 數據庫讀取數據並通過 API 返回客戶端的項目。 從安全的角度來看,最好進行投影(顯式字段復制)以避免將來添加任何返回給客戶端的字段。 我正在尋找一種簡單的方法來做到這一點。

// ----------
// TypeScript type definition
// ----------
interface Student {
  name: string
  studentId?: string
}

interface StudentDbRecord extends Student {
  createTimestamp: number
}

interface StudentApiResult extends Student {
  // We use NoSQL, so ID is not part of the record
  id: string
}

// ----------
// Database data
// ----------
const docId: string = '6542fdba-fcae-4b15-a1c8-72a2a57f51c7'
const dbRecord: StudentDbRecord = {
  name: 'Chirs',
  createTimestamp: Date.now()
}

// ----------
// Implementation
// ----------
// Method 1: An extra `createTimestamp` field is in `apiResult1` and returned to API caller
const apiResult1: StudentApiResult = {
  ...dbRecord,
  id: docId
}

const apiResult2: StudentApiResult = {
  id: docId,
  name: dbRecord.name,
  // Method 2: This result in a field with `undefined` value, which causes other issues
  studentId: dbRecord.studentId
}

// Method 3: This works, but easier to make mistake because `studentId` is specified 3 times
const apiResult3: StudentApiResult = {
  id: docId,
  name: dbRecord.name
}
if (dbRecord.studentId !== null) { apiResult3.studentId = dbRecord.studentId }

// Method 4, this should be the best but unable to get it working in TypeScript
function copyField<D, S, K extends (keyof D & keyof S)>(dest: D, src: S, key: K): void {
  if (src[key] !== undefined) {
    // Error ts(2322): 'D' could be instantiated with an arbitrary type which could be unrelated to 'S'
    dest[key] = src[key]
  }
}

const apiResult4: StudentApiResult = {
  id: docId,
  name: dbRecord.name
}
copyField(apiResult4, dbRecord, 'studentId')

訣竅是只提交入站 dest 和 src 對象的最少類型。 看看我為你制作的最小復制品和這個游樂場的潛在解決方案

function copyField<Key extends keyof any, Value>(
  key: Key,
  source: { [K in Key]: Value },
  dest: { [K in Key]: Value }
): void {
  const sourceValue = source[key];
  if (sourceValue !== undefined) {
    dest[key] = sourceValue;
  }
}

const rover: Dog = {
  hasFleas: true,
  hasStick: false,
};

const felix: Cat = {
  hasFleas: false,
  hasMouse: true,
};

const klaus: Fish = {
  hasTeeth: false,
};

copyField("hasFleas", rover, felix);

//this is (correctly) a compiler error
copyField("hasFleas", felix, klaus);

interface Dog {
  hasFleas: boolean;
  hasStick: boolean;
}

interface Cat {
  hasFleas: boolean;
  hasMouse: boolean;
}

interface Fish {
  hasTeeth: boolean;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM