Another TypeScript Type Challenge with a C++ port. This one is like the last one (Pick), but instead of only picking selected fields we make selected fields readonly and carry over the rest.
TypeScript Challenge
The TypeScript challenge is pretty straightforward. Given an interface, make every field read-only. Here’s the challenge code:
type MyReadonly<T> = any
/* _____________ Test Cases _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect<Equal<MyReadonly<Todo1>, Readonly<Todo1>>>,
]
interface Todo1 {
title: string
description: string
completed: boolean
meta: {
author: string
}
}The solution is pretty trivial. We just apply the readonly modifier to every key in an interface. The only tricky thing is where readonly goes.
type MyReadonly<T> = {
readonly [Key in keyof T]: T[Key]
}C++ Challenge
I’m really starting to feel the missing reflection in C++’s type system. Unfortunately, at time of writing only GCC 16 has support, and it has an asterisk. So anyone using the OS vendor compiler for Windows or MacOS or just using an older GCC (like on Debian) just wouldn’t be able to do the challenge if C++26 reflection was mandated. So, I again simplified the challenge. I, unfortunately, believe this will become a bit of a theme.
For the C++ challenge, we will always have three fields: title, description, completed. I’m not adding additional fields because that’s just tedium. The goal is to make each field const. Here’s the challenge code:
template<class RefType>
struct Const;
/*************************************
* Tests
*************************************/
struct Todo {
std::string title;
const std::string description;
bool completed;
};
struct Assignment {
std::string_view title;
std::string_view description;
int completed;
};
template<typename T, typename I>
constexpr bool titleShouldBeConst =
std::is_same_v<decltype(std::declval<T>().title), std::add_const_t<decltype(std::declval<I>().title)>>;
template<typename T, typename I>
constexpr bool descriptionShouldBeConst =
std::is_same_v<decltype(std::declval<T>().description), std::add_const_t<decltype(std::declval<I>().description)>>;
template<typename T, typename I>
constexpr bool completedShouldBeConst =
std::is_same_v<decltype(std::declval<T>().completed), std::add_const_t<decltype(std::declval<I>().completed)>>;
using TestType1 = Const<Todo>;
static_assert(titleShouldBeConst<TestType1, Todo>);
static_assert(descriptionShouldBeConst<TestType1, Todo>);
static_assert(completedShouldBeConst<TestType1, Todo>);
using TestType2 = Const<Assignment>;
static_assert(titleShouldBeConst<TestType2, Assignment>);
static_assert(descriptionShouldBeConst<TestType2, Assignment>);
static_assert(completedShouldBeConst<TestType2, Assignment>);
C++ Solution
This solution is at least trivial, but that’s mainly because I had to simplify it enough to be doable without reflection. The tricky part would be where to put the keyword, except C++ has a builtin that already does that for us. So we just use that instead:
template<class RefType>
struct Const {
std::add_const_t<decltype(std::declval<RefType>().title)> title;
std::add_const_t<decltype(std::declval<RefType>().description)> description;
std::add_const_t<decltype(std::declval<RefType>().completed)> completed;
};At last, we have a fairly simple solution in C++. I’ve looked ahead, and there are a few more simple challenges, but some of them are going to be anything but simple. And some of them may not be po

