Typescript高級: 深入理解extends keyof語法

概述

  • 在TypeScript中,extends關鍵字是類型系統中一個極其重要的組成部分
  • 它不僅用于類的繼承,也是類型兼容性檢查和泛型約束的關鍵機制
  • 特別是當它與keyof關鍵字結合,形成K extends keyof T的結構時
  • 它為類型系統帶來了強大的靈活性和表達能力,讓我們能夠在泛型中對對象的屬性進行操作和約束

K extends keyof T

  • 在TypeScript中,當你聲明一個泛型約束為K extends keyof T
  • 這意味著泛型參數K被限制為只能是T類型上存在的屬性名的子集
  • 這在處理對象屬性、映射類型或者條件類型時非常有用

示例1

interface User {id: number;name: string;email: string;
}function getProperty<T, K extends keyof T>(user: T, key: K): T[K] {return user[key];
}const user = { id: 1, name: "Alice", email: "alice@example.com"};
console.log(getProperty(user, "name")); // 輸出 "Alice"
  • 在這個例子中,K extends keyof User 確保了getProperty函數的key參數, 只能是User接口中定義的屬性名

示例2 屬性全面轉化成只讀

interface User {id: number;name: string;email: string;
}type ReadonlyStringFields<T> = {readonly [P in keyof T]: T[P];}type ReadonlyUser = ReadonlyStringFields<User>;// ReadonlyUser 類型為:
// {
//   id: number;
//   readonly name: string;
//   readonly email: string;
// }
  • 這里,ReadonlyStringFields 將所有屬性轉化為只讀,當然

示例3:部分屬性只讀

type MakeSomePropertiesReadonly<T, K extends keyof T> = {readonly [P in K]: T[P];
} & {[P in Exclude<keyof T, K>]: T[P];
};interface UserInfo {id: number;username: string;email: string;isAdmin: boolean;
}type ReadonlyUserDetails = MakeSomePropertiesReadonly<UserInfo, 'id' | 'email'>;function displayUserInfo(user: ReadonlyUserDetails) {console.log(`ID: ${user.id}, Email: ${user.email}`);// 下面這行如果嘗試在真實代碼中執行,會因為類型檢查而在編譯時失敗// user.id = 123; // Error: Cannot assign to 'id' because it is a read-only property.user.username = "NewUsername"; // 這是允許的,因為 username 不是只讀的
}// 假設我們有一個UserInfo實例,為了演示,直接構造一個符合 ReadonlyUserDetails 的對象
const userDetails: ReadonlyUserDetails = {id: 42,username: "JohnDoe",email: "john.doe@example.com",isAdmin: false,
};displayUserInfo(userDetails);
  • 在 MakeSomePropertiesReadonly<T, K>
  • 泛型參數:
    • T: 表示你想要修改屬性可讀性的原始對象類型
    • K extends keyof T: 表示一個泛型約束,要求 K 必須是 T 類型的鍵(即屬性名)的一個子集。這意味著你可以指定 T 中任意數量和名稱的屬性來變為只讀
  • 類型別名結構:
    • { readonly [P in K]: T[P]; }: 這部分創建了一個新類型,其中 K 集合內的每個屬性 P 被聲明為只讀。[P in K] 是一個映射類型,遍歷 K 中的所有鍵,并為每個鍵創建一個屬性,其值類型與 T[P] 相同,但加上了 readonly 修飾符。
    • & { [P in Exclude<keyof T, K>]: T[P]; } 這部分用來保留 T 類型中未被指定為只讀的那些屬性。Exclude<keyof T, K> 是一個實用類型,用于從 T 的所有鍵中排除已經在 K 中的鍵,確保剩余的屬性不被重復定義且保持原樣。

K extends keyof any

  • 當K extends keyof any時,這個約束實際上沒有起到任何限制作用
  • 因為any類型在TypeScript中是最寬泛的類型,表示可以代表任何類型,所以任何類型都可以被認為是any的鍵
  • 這通常在你想要泛型參數可以是任何類型時使用,但這種用法在實踐中較少見,因為失去了類型安全性的優勢

示例

function getProperty<K extends keyof any>(obj: any, key: K): any {  return obj[key];  
}  const person = {  name: 'Alice',  age: 30,  address: '123 Main Street'  
};  // 由于使用了 keyof any,我們可以傳入任何類型的鍵  
const name = getProperty(person, 'name'); // string  
const age = getProperty(person, 'age'); // number  
const address = getProperty(person, 'address'); // string  
const unknownProp = getProperty(person, 'unknownProp'); // undefined,但不會引發類型錯誤  console.log(name); // 輸出: Alice  
console.log(age); // 輸出: 30  
console.log(address); // 輸出: 123 Main Street  
console.log(unknownProp); // 輸出: undefined
  • keyof any表示任何可能的屬性名,因為any類型可以包含任意屬性
  • 使用K extends keyof any實際上對K沒有太多限制,它可以是任意字符串或符號
  • 這種約束通常不是很有用,因為它不提供關于K具體可能是什么的明確信息

K extends keyof (string | number | symbol)

  • 這個表達式意味著泛型參數K可以是string或symbol類型中任何一個的鍵名
  • 在TypeScript中,對象的鍵通常是字符串或符號類型,但不包括數字(除非使用了計算屬性名)
  • 因此,這個約束在直覺上可能用于處理特殊情況,比如當你知道泛型參數可能被用于索引一個映射到字符串或符號屬性上,但實際上在標準對象操作中,數字作為鍵的用法不常見

示例

type AcceptableKeys = string | number | symbol;  function processKey<K extends AcceptableKeys>(key: K): void {console.log(`Processing key: ${key.toString()}`);  
}  // 使用字符串作為鍵  
processKey("myStringKey");  
// 使用數字作為鍵  
processKey(123);  // 使用符號作為鍵  
const mySymbol = Symbol("mySymbol");  
processKey(mySymbol);
  • 在這個示例中,我們定義了一個類型別名 AcceptableKeys,它表示可以接受的鍵類型是字符串、數字或符號
  • 然后,我們定義了一個泛型函數 processKey,它接受一個類型為 K 的參數,其中 K 被約束為必須擴展(extends)AcceptableKeys
  • 這樣,我們就可以向 processKey 函數傳遞字符串、數字或符號類型的參數

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/21179.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/21179.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/21179.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

動態SQL where, choose語句

where語句就一個<where>標簽, 很簡單, 不再過多贅述 接下來我們來看 choose語句的使用 其實choose語句就像java里的swith語句 , 如果語句前面的生效 , 后面的就不會生效了 可以定義查詢的優先級

讀人工智能時代與人類未來筆記19_讀后總結與感想兼導讀

1. 基本信息 人工智能時代與人類未來 (美)亨利基辛格,(美)埃里克施密特,(美)丹尼爾胡滕洛赫爾 著 中信出版社,2023年6月出版 1.1. 讀薄率 書籍總字數145千字&#xff0c;筆記總字數39934字。 讀薄率39934145000≈27.5% 1.2. 讀厚方向 千腦智能 腦機穿越 未來呼嘯而來 …

【工具】 MyBatis Plus的SQL攔截器自動翻譯替換“?“符號為真實數值

【工具】 MyBatis Plus的SQL攔截器自動翻譯替換"?"符號為真實數值 使用MyBatis的配置如下所示&#xff1a; mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl調用接口&#xff0c;sql日志打印如下&#xff1a; 參數和sql語句不…

Spring Boot配置MySQL數據庫連接數

1.如何在Spring Boot中配置MySQL數據庫的連接數 1.1主要配置 在Spring Boot中配置MySQL數據庫連接數通常涉及到兩個主要的配置&#xff1a; &#xff08;1&#xff09;數據源配置&#xff1a;這通常是在application.properties或application.yml文件中完成的&#xff0c;用于…

頂底背離的終極猜想和運用

這幾天圈內都在傳底蓓離什么的。作為嚴肅的量化自媒體&#xff0c;我們就不跟著吃這波瓜了。不過&#xff0c;我一直很關注技術指標的頂背離和底背離&#xff0c;一直在追問它的成因如何&#xff0c;以及如何預測。 底蓓離把我目光再次吸引到這個領域來&#xff0c;于是突然有…

Java如何實現二維數組行列轉換

二維數組行列轉換就是行號和列號互換 public class Erweishuzubianli {public static void main(String[] args) {int array[][]new int[][]{{8,75,23},{21,55,34},{15,23,20}};int temp;for(int i0;i<array.length;i){for(int j0;j<array[i].length;j){temparray[i][j]…

LitCTF 2024(公開賽道)——WP

目錄 Misc 涐貪戀和伱、甾―⑺d毎兮毎秒 你說得對&#xff0c;但__ 盯幀珍珠 Everywhere We Go 關鍵&#xff0c;太關鍵了! 女裝照流量 原鐵&#xff0c;啟動&#xff01; 舔到最后應有盡有 The love Web exx 一個....池子&#xff1f; SAS - Serializing Authent…

MySQL—函數—日期函數(基礎)

一、引言 接下來討論和學習關于函數的第三個方面——日期函數。 常見的MySQL當中的日期函數。 注意&#xff1a; 1、CURDATE()&#xff1a;cur&#xff1a;current 當前的&#xff0c;返回的是當前日期。 2、CURTIME()&#xff1a;當前時間。 3、NOW&#xff1a;當前的日期和…

Java語言高級編程:探索深層機制與應用技巧

Java語言高級編程&#xff1a;探索深層機制與應用技巧 在編程世界中&#xff0c;Java以其穩定、強大和跨平臺的特性贏得了廣泛的贊譽和應用。對于已經掌握Java基礎知識的開發者來說&#xff0c;深入Java語言的高級編程領域&#xff0c;無疑將開啟全新的技術視野。那么&#xf…

政安晨【零基礎玩轉各類開源AI項目】:解析開源項目的論文:Physical Non-inertial Poser (PNP)

政安晨的個人主頁&#xff1a;政安晨 歡迎 &#x1f44d;點贊?評論?收藏 收錄專欄: 零基礎玩轉各類開源AI項目 希望政安晨的博客能夠對您有所裨益&#xff0c;如有不足之處&#xff0c;歡迎在評論區提出指正&#xff01; 本文解析的原始論文為&#xff1a;https://arxiv.org/…

力扣1143. 最長公共子序列

給定兩個字符串 text1 和 text2&#xff0c;返回這兩個字符串的最長 公共子序列 的長度。如果不存在 公共子序列 &#xff0c;返回 0 。 一個字符串的 子序列 是指這樣一個新的字符串&#xff1a;它是由原字符串在不改變字符的相對順序的情況下刪除某些字符&#xff08;也可以…

【TB作品】MSP430G2533,讀取dht11,顯示到lcd1602顯示屏,串口發送到電腦

功能 讀取dht11&#xff0c;顯示到lcd1602顯示屏&#xff0c;串口發送到電腦。 部分程序 void main(void) {char disp[20];char count 0;WDTCTL WDTPW WDTHOLD; // Stop WDTP1DIR 0Xff;P1SEL 0X00;P1SEL2 0X00;P2DIR 0Xff;P2SEL 0X00;P2SEL2 0X00;L…

為什么需要開局調用函數?

初始化操作&#xff1a;在你的應用程序啟動時&#xff0c;可能需要執行一些初始化操作&#xff0c;例如設置默認值、加載配置、建立數據庫連接等。開局調用函數可以幫助你集中管理這些操作&#xff0c;確保它們在應用程序啟動時順利執行。 統一入口&#xff1a;通過一個統一的…

打造你的專屬Vue組件:基于FullCalendar超實用“日程任務管理組件”實戰

打造你的專屬Vue組件&#xff1a;基于FullCalendar超實用“日程任務管理組件”實戰 在現代Web應用中&#xff0c;日程管理是一個常見而又關鍵的功能&#xff0c;它幫助用戶高效安排和追蹤日常任務及會議。Vue.js作為一個流行的前端框架&#xff0c;以其簡潔的語法和強大的組件…

編譯選項導致的結構體字節參數異常

文章目錄 前言問題描述原因分析問題解決總結 前言 在構建編譯工程時&#xff0c;會有一些對應的編譯配置選項&#xff0c;不同的編譯器&#xff0c;會有對應的配置項。本文介紹GHS工程中編譯選項配置不對應導致的異常。 問題描述 在S32K3集成工程中&#xff0c;核1的INP_SWC…

transformer中的ffn

## import torch import torch.nn as nn import torch.nn.functional as F import logging logging.basicConfig(levellogging.INFO, format%(asctime)s %(levelname)s: %(message)s) # 定義FFN層 class FeedForwardNetwork(nn.Module): def __init__(self, input_dim, hi…

python運營商身份證二要素查驗接口、身份證實名認證接口

隨著網絡服務安全需求的日益增長&#xff0c;個人信息的真實性和安全性成為了眾多在線平臺關注的焦點。近日&#xff0c;為應對這一挑戰&#xff0c;翔云人工智能接口開放平臺提供了Python語言的身份證二要素查驗接口”及“實名認證接口”&#xff0c;旨在為各行業提供高效、準…

將字符串 “()“ ““ “|“ 條件組成的復雜表達式轉換為ES查詢語句

應用場景 "()" "&" "|" 這幾個條件對于我們來說并不陌生, 其表達的邏輯非常明了, 又能通過很少的字符表達很復雜的嵌套關系, 在一些復雜的查詢中會經常用到, 因此我最近也遇到了類似的問題,一開始覺得這類的工具應該挺常見的, 結果搜了半天…

JVM垃圾收集器和內存分配策略

概述 Java內存運行時數據區的程序計數器、虛擬機棧、本地方法棧3個區域會隨著線程而產生&#xff0c;隨線程而消失。這幾個區域分配多少內存時在類結構確定下來即已知的&#xff0c;在這幾個區域內就不需要過多考慮如何回收內存的問題&#xff0c;當方法結束或者線程結束時&am…

【spring】第一篇 IOC和DI入門案例

Spring到底是如何來實現IOC和DI的&#xff0c;那接下來就通過一些簡單的入門案例&#xff0c;來演示下具體實現過程。 目錄 前期準備 一、IOC入門案例 思路分析 代碼實現 二、DI入門案例 思路分析 代碼實現 總結 前期準備 使用IDEA創建Maven項目&#xff0c;首先需要配…