mirror of
https://github.com/type-challenges/type-challenges.git
synced 2026-02-01 15:47:22 +00:00
feat: two more challenges
This commit is contained in:
parent
09984c07cf
commit
df6f2b30e9
@ -34,7 +34,7 @@ English | <a href='./README.zh-CN.md'>简体中文</a>
|
||||
> Click the following badges to see detail of the challenges!
|
||||
|
||||
<!--challenges-start-->
|
||||
<a href="./questions/2-medium-return-type/README.md" target="_blank"><img src="https://img.shields.io/badge/-%232%E3%83%BBGet%20Return%20Type-d8af2c" alt="#2・Get Return Type"/></a> <a href="./questions/3-medium-omit/README.md" target="_blank"><img src="https://img.shields.io/badge/-%233%E3%83%BBOmit%3CT%2C%20K%3E-d8af2c" alt="#3・Omit<T, K>"/></a> <a href="./questions/4-easy-pick/README.md" target="_blank"><img src="https://img.shields.io/badge/-%234%E3%83%BBPick%3CT%2C%20K%3E-green" alt="#4・Pick<T, K>"/></a> <a href="./questions/5-hard-readonly-keys/README.md" target="_blank"><img src="https://img.shields.io/badge/-%235%E3%83%BBGet%20Readonly%20Keys-red" alt="#5・Get Readonly Keys"/></a> <a href="./questions/6-extreme-simple-vue/README.md" target="_blank"><img src="https://img.shields.io/badge/-%236%E3%83%BBSimple%20Vue-purple" alt="#6・Simple Vue"/></a>
|
||||
<a href="./questions/2-medium-return-type/README.md" target="_blank"><img src="https://img.shields.io/badge/-%232%E3%83%BBGet%20Return%20Type-d8af2c" alt="#2・Get Return Type"/></a> <a href="./questions/3-medium-omit/README.md" target="_blank"><img src="https://img.shields.io/badge/-%233%E3%83%BBOmit%3CT%2C%20K%3E-d8af2c" alt="#3・Omit<T, K>"/></a> <a href="./questions/4-easy-pick/README.md" target="_blank"><img src="https://img.shields.io/badge/-%234%E3%83%BBPick%3CT%2C%20K%3E-green" alt="#4・Pick<T, K>"/></a> <a href="./questions/5-hard-readonly-keys/README.md" target="_blank"><img src="https://img.shields.io/badge/-%235%E3%83%BBGet%20Readonly%20Keys-red" alt="#5・Get Readonly Keys"/></a> <a href="./questions/6-extreme-simple-vue/README.md" target="_blank"><img src="https://img.shields.io/badge/-%236%E3%83%BBSimple%20Vue-purple" alt="#6・Simple Vue"/></a> <a href="./questions/7-easy-readonly/README.md" target="_blank"><img src="https://img.shields.io/badge/-%237%E3%83%BBReadonly%3CT%3E-green" alt="#7・Readonly<T>"/></a> <a href="./questions/8-medium-readonly-2/README.md" target="_blank"><img src="https://img.shields.io/badge/-%238%E3%83%BBReadonly%202-d8af2c" alt="#8・Readonly 2"/></a>
|
||||
<!--challenges-end-->
|
||||
|
||||
</details>
|
||||
|
||||
@ -28,7 +28,7 @@ TypeScript 类型体操姿势合集
|
||||
> 点击下方徽章查看挑战内容
|
||||
|
||||
<!--challenges-start-->
|
||||
<a href="./questions/2-medium-return-type/README.zh-CN.md" target="_blank"><img src="https://img.shields.io/badge/-%232%E3%83%BB%E8%8E%B7%E5%8F%96%E5%87%BD%E6%95%B0%E8%BF%94%E5%9B%9E%E7%B1%BB%E5%9E%8B-d8af2c" alt="#2・获取函数返回类型"/></a> <a href="./questions/3-medium-omit/README.md" target="_blank"><img src="https://img.shields.io/badge/-%233%E3%83%BB%E5%AE%9E%E7%8E%B0%20Omit%3CT%2C%20K%3E-d8af2c" alt="#3・实现 Omit<T, K>"/></a> <a href="./questions/4-easy-pick/README.md" target="_blank"><img src="https://img.shields.io/badge/-%234%E3%83%BB%E5%AE%9E%E7%8E%B0%20Pick%3CT%2C%20K%3E-green" alt="#4・实现 Pick<T, K>"/></a> <a href="./questions/5-hard-readonly-keys/README.md" target="_blank"><img src="https://img.shields.io/badge/-%235%E3%83%BB%E8%8E%B7%E5%8F%96%E5%8F%AA%E8%AF%BB%E5%AD%97%E6%AE%B5-red" alt="#5・获取只读字段"/></a> <a href="./questions/6-extreme-simple-vue/README.md" target="_blank"><img src="https://img.shields.io/badge/-%236%E3%83%BB%E7%AE%80%E5%8D%95%E7%9A%84%20Vue%20%E7%B1%BB%E5%9E%8B-purple" alt="#6・简单的 Vue 类型"/></a>
|
||||
<a href="./questions/2-medium-return-type/README.zh-CN.md" target="_blank"><img src="https://img.shields.io/badge/-%232%E3%83%BB%E8%8E%B7%E5%8F%96%E5%87%BD%E6%95%B0%E8%BF%94%E5%9B%9E%E7%B1%BB%E5%9E%8B-d8af2c" alt="#2・获取函数返回类型"/></a> <a href="./questions/3-medium-omit/README.md" target="_blank"><img src="https://img.shields.io/badge/-%233%E3%83%BB%E5%AE%9E%E7%8E%B0%20Omit%3CT%2C%20K%3E-d8af2c" alt="#3・实现 Omit<T, K>"/></a> <a href="./questions/4-easy-pick/README.md" target="_blank"><img src="https://img.shields.io/badge/-%234%E3%83%BB%E5%AE%9E%E7%8E%B0%20Pick%3CT%2C%20K%3E-green" alt="#4・实现 Pick<T, K>"/></a> <a href="./questions/5-hard-readonly-keys/README.md" target="_blank"><img src="https://img.shields.io/badge/-%235%E3%83%BB%E8%8E%B7%E5%8F%96%E5%8F%AA%E8%AF%BB%E5%AD%97%E6%AE%B5-red" alt="#5・获取只读字段"/></a> <a href="./questions/6-extreme-simple-vue/README.md" target="_blank"><img src="https://img.shields.io/badge/-%236%E3%83%BB%E7%AE%80%E5%8D%95%E7%9A%84%20Vue%20%E7%B1%BB%E5%9E%8B-purple" alt="#6・简单的 Vue 类型"/></a> <a href="./questions/7-easy-readonly/README.md" target="_blank"><img src="https://img.shields.io/badge/-%237%E3%83%BB%E5%AE%9E%E7%8E%B0%20Readonly%3CT%3E-green" alt="#7・实现 Readonly<T>"/></a> <a href="./questions/8-medium-readonly-2/README.md" target="_blank"><img src="https://img.shields.io/badge/-%238%E3%83%BBReadonly%202-d8af2c" alt="#8・Readonly 2"/></a>
|
||||
<!--challenges-end-->
|
||||
|
||||
## 参与贡献
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<!--info-header-start-->
|
||||
# Omit<T, K> <img src="https://img.shields.io/badge/-medium-d8af2c" alt="medium"/>
|
||||
# Omit\<T, K\> <img src="https://img.shields.io/badge/-medium-d8af2c" alt="medium"/>
|
||||
> by Anthony Fu
|
||||
|
||||
<a href="https://type-challenges.netlify.app/case/3/play/en" target="_blank"><img src="https://img.shields.io/badge/-Take%20the%20Challenge-blue?logo=typescript" alt="Take the Challenge"/></a> <!--info-header-end-->
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<!--info-header-start-->
|
||||
# Pick<T, K> <img src="https://img.shields.io/badge/-easy-green" alt="easy"/>
|
||||
# Pick\<T, K\> <img src="https://img.shields.io/badge/-easy-green" alt="easy"/>
|
||||
> by Anthony Fu
|
||||
|
||||
<a href="https://type-challenges.netlify.app/case/4/play/en" target="_blank"><img src="https://img.shields.io/badge/-Take%20the%20Challenge-blue?logo=typescript" alt="Take the Challenge"/></a> <!--info-header-end-->
|
||||
|
||||
31
questions/7-easy-readonly/README.md
Normal file
31
questions/7-easy-readonly/README.md
Normal file
@ -0,0 +1,31 @@
|
||||
<!--info-header-start-->
|
||||
# Readonly\<T\> <img src="https://img.shields.io/badge/-easy-green" alt="easy"/>
|
||||
> by Anthony Fu
|
||||
|
||||
<a href="https://type-challenges.netlify.app/case/7/play/en" target="_blank"><img src="https://img.shields.io/badge/-Take%20the%20Challenge-blue?logo=typescript" alt="Take the Challenge"/></a> <!--info-header-end-->
|
||||
|
||||
|
||||
Implement the built-in `Readonly<T>` generic without using it.
|
||||
|
||||
Constructs a type with all properties of T set to readonly, meaning the properties of the constructed type cannot be reassigned.
|
||||
|
||||
For example
|
||||
|
||||
```ts
|
||||
interface Todo {
|
||||
title: string
|
||||
description: string
|
||||
}
|
||||
|
||||
const todo: MyReadonly<Todo> = {
|
||||
title: "Hey",
|
||||
description: "foobar"
|
||||
}
|
||||
|
||||
todo.title = "Hello" // Error: cannot reassign a readonly property
|
||||
todo.description = "barFoo" // Error: cannot reassign a readonly property
|
||||
```
|
||||
|
||||
<!--info-footer-start-->
|
||||
<a href="../../README.md" target="_blank"><img src="https://img.shields.io/badge/-Back-grey" alt="Back"/></a> <a href="https://type-challenges.netlify.app/case/7/answers" target="_blank"><img src="https://img.shields.io/badge/-Check%20out%20Answers-F59BAF?logo=awesome-lists&logoColor=white" alt="Check out Answers"/></a>
|
||||
<!--info-footer-end-->
|
||||
8
questions/7-easy-readonly/info.yml
Normal file
8
questions/7-easy-readonly/info.yml
Normal file
@ -0,0 +1,8 @@
|
||||
title: Readonly<T>
|
||||
|
||||
author:
|
||||
name: Anthony Fu
|
||||
email: hi@antfu.me
|
||||
github: antfu
|
||||
|
||||
tags: built-in, readonly, object-keys
|
||||
1
questions/7-easy-readonly/info.zh-CN.yml
Normal file
1
questions/7-easy-readonly/info.zh-CN.yml
Normal file
@ -0,0 +1 @@
|
||||
title: 实现 Readonly<T>
|
||||
1
questions/7-easy-readonly/template.ts
Normal file
1
questions/7-easy-readonly/template.ts
Normal file
@ -0,0 +1 @@
|
||||
type MyReadonly<T> = any
|
||||
11
questions/7-easy-readonly/test-cases.ts
Normal file
11
questions/7-easy-readonly/test-cases.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { Equal, Expect } from '@type-challenges/utils'
|
||||
|
||||
type cases = [
|
||||
Expect<Equal<MyReadonly<Todo1>, Readonly<Todo1>>>,
|
||||
]
|
||||
|
||||
interface Todo1 {
|
||||
title: string
|
||||
description: string
|
||||
completed: boolean
|
||||
}
|
||||
33
questions/8-medium-readonly-2/README.md
Normal file
33
questions/8-medium-readonly-2/README.md
Normal file
@ -0,0 +1,33 @@
|
||||
<!--info-header-start-->
|
||||
# Readonly 2 <img src="https://img.shields.io/badge/-medium-d8af2c" alt="medium"/>
|
||||
> by Anthony Fu
|
||||
|
||||
<a href="https://type-challenges.netlify.app/case/8/play/en" target="_blank"><img src="https://img.shields.io/badge/-Take%20the%20Challenge-blue?logo=typescript" alt="Take the Challenge"/></a> <!--info-header-end-->
|
||||
|
||||
Implement a generic `MyReadonly2<T, K>` which takes two type argument `T` and `K`.
|
||||
|
||||
`K` specify the set of properties if `T` that should set to Readonly. When `K` is not provided, it should make all properties readonly just like the normal `Readonly<T>`.
|
||||
|
||||
For example
|
||||
|
||||
```ts
|
||||
interface Todo {
|
||||
title: string
|
||||
description: string
|
||||
completed: boolean
|
||||
}
|
||||
|
||||
const todo: MyReadonly2<Todo, 'title' | 'description'> = {
|
||||
title: "Hey",
|
||||
description: "foobar",
|
||||
completed: false,
|
||||
}
|
||||
|
||||
todo.title = "Hello" // Error: cannot reassign a readonly property
|
||||
todo.description = "barFoo" // Error: cannot reassign a readonly property
|
||||
todo.completed = true // OK
|
||||
```
|
||||
|
||||
<!--info-footer-start-->
|
||||
<a href="../../README.md" target="_blank"><img src="https://img.shields.io/badge/-Back-grey" alt="Back"/></a> <a href="https://type-challenges.netlify.app/case/8/answers" target="_blank"><img src="https://img.shields.io/badge/-Check%20out%20Answers-F59BAF?logo=awesome-lists&logoColor=white" alt="Check out Answers"/></a>
|
||||
<!--info-footer-end-->
|
||||
8
questions/8-medium-readonly-2/info.yml
Normal file
8
questions/8-medium-readonly-2/info.yml
Normal file
@ -0,0 +1,8 @@
|
||||
title: Readonly 2
|
||||
|
||||
author:
|
||||
name: Anthony Fu
|
||||
email: hi@antfu.me
|
||||
github: antfu
|
||||
|
||||
tags: readonly, object-keys
|
||||
1
questions/8-medium-readonly-2/info.zh-CN.yml
Normal file
1
questions/8-medium-readonly-2/info.zh-CN.yml
Normal file
@ -0,0 +1 @@
|
||||
title: Readonly 2
|
||||
1
questions/8-medium-readonly-2/template.ts
Normal file
1
questions/8-medium-readonly-2/template.ts
Normal file
@ -0,0 +1 @@
|
||||
type MyReadonly2<T, K> = any
|
||||
18
questions/8-medium-readonly-2/test-cases.ts
Normal file
18
questions/8-medium-readonly-2/test-cases.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { Equal, Expect } from '@type-challenges/utils'
|
||||
|
||||
type cases = [
|
||||
Expect<Equal<MyReadonly2<Todo1>, Readonly<Todo1>>>,
|
||||
Expect<Equal<MyReadonly2<Todo1, 'title' | 'description'>, Expected>>,
|
||||
]
|
||||
|
||||
interface Todo1 {
|
||||
title: string
|
||||
description?: string
|
||||
completed: boolean
|
||||
}
|
||||
|
||||
interface Expected {
|
||||
readonly title: string
|
||||
readonly description?: string
|
||||
completed: boolean
|
||||
}
|
||||
@ -13,6 +13,12 @@ const DifficultyColors: Record<string, string> = {
|
||||
extreme: 'purple',
|
||||
}
|
||||
|
||||
function escape(text: string) {
|
||||
return text
|
||||
.replace(/</, '\\<')
|
||||
.replace(/>/, '\\>')
|
||||
}
|
||||
|
||||
function toBadgeURL(label: string, text: string, color: string, args = '') {
|
||||
return `https://img.shields.io/badge/${encodeURIComponent(label.replace(/-/g, '--'))}-${encodeURIComponent(text.replace(/-/g, '--'))}-${color}${args}`
|
||||
}
|
||||
@ -42,7 +48,7 @@ async function insertInfoReadme(filepath: string, quiz: Quiz, locale: keyof type
|
||||
.replace(
|
||||
/<!--info-header-start-->[\s\S]*<!--info-header-end-->/,
|
||||
'<!--info-header-start-->\n'
|
||||
+ `# ${info.title} ${toBadge('', quiz.difficulty, DifficultyColors[quiz.difficulty])}\n`
|
||||
+ `# ${escape(info.title || '')} ${toBadge('', quiz.difficulty, DifficultyColors[quiz.difficulty])}\n`
|
||||
+ `> by ${info.author?.name}\n\n`
|
||||
+ toBadgeLink(toPlay(quiz.no, locale), '', messages[locale]['take-the-challenge'], 'blue', '?logo=typescript')
|
||||
+ '<!--info-header-end-->',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user