How to override local module interface in TypeScript? - reactjs

I have a "library framework" nested inside my Next.js project (for now, as I don't want to go through the process of making it a standalone package yet). In that project I declare a few types, interfaces, and variables in one module, and then I try to override one of the interfaces from outside that module at the top-level of my app. So I have basically this:
components/
styles.ts // define interface here
package.d.ts // override module interface here
In package.d.ts I have this:
type AppFont = {
amharic: true
arabic: true
armenian: true
bengali: true
burmese: true
chinese: true
georgian: true
hebrew: true
hindi: true
inuktitut: true
japanese: true
kannada: true
khmer: true
korean: true
latin: true
malayalam: true
persian: true
tamil: true
text: true
thai: true
tibetan: true
}
declare module './components/styles' {
interface Font extends AppFont {}
}
In component/styles.ts I have this (amongst other variables and types):
export interface Font {
arial: true
}
export interface Theme {}
Also in my outer app I have this:
import { Font } from 'components/styles'
const fonts: Record<keyof Font, string> = {
amharic: 'Amharic',
arabic: 'Arabic',
armenian: 'Armenian',
bengali: 'Bengali',
burmese: 'Burmese',
chinese: 'Chinese',
georgian: 'Georgian',
hebrew: 'Hebrew',
hindi: 'Hindi',
inuktitut: 'Inuktitut',
japanese: 'Japanese',
kannada: 'Kannada',
khmer: 'Khmer',
korean: 'Korean',
latin: 'Latin',
malayalam: 'Malayalam',
persian: 'Persian',
tamil: 'Tamil',
text: 'text',
thai: 'Thai',
tibetan: 'Tibetan',
}
export const theme = {
fonts
}
export type AppTheme = typeof theme
So my final attempt at module override in package.d.ts looks like this:
declare module './components/styles' {
interface Font extends AppFont {}
interface Theme extends AppTheme {}
}
I then have a component like this inside the "nested library" (components/MyComponent.tsx):
type ComponentPropsType = {
font: keyof Font
}
export default function Component({
font,
}: ComponentPropsType) {
...
}
Since this component is in the library, it only has access to arial font. But since I overrode it, it should now accept all the fonts in the list. However, I am getting an error when I try and reference "tamil" font for example. So it's not picking it up.
What am I doing wrong? I am referencing the links here.

Related

how to implement jsx as a class property for downstream resolution?

I've created the following interface:
export interface DataColumn {
fieldName: string,
columnHeaderName: string,
fieldValue: any;
className: string;
headerClassName: string;
template: JSX.Element | undefined;
}
The last property reflects an optional template. If provided then it should override the default generic fieldValue display. The goal is to render out the template in the downstream component like this:
{template}
But I'm not clear on how to instantiate the value for this property in the intermediate component. I tried the following code:
template: new JSX.Element(<div>THIS IS MY JSX TEST</div>)
But that code returns the following error:
Cannot use namespace 'JSX' as a value.ts(2708)
So what's the proper way to set a class property with a JSX value which can then be dynamically rendered as JSX in a downstream component?

Types for tailwind

I am using tailwind.config.js in order to extend some colors:
const theme = {
mode: 'jit',
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
darkMode: 'media', // 'media' or 'class'
theme: {
extend: {
colors: {}
but then I might pass a color to a component in props in order to later use it as border-${color} and/or text-${color}.
Right now the value would be just of type string so I am not getting the tips, is there some way to get a type of the combined custom colors + default tailwind's colors ?
You have to return the complete string border-red-500 in place of border-${color}.
Like you can define a function like this
let {color} = props;
function getColor( color) {
return 'border-" + color;
}
And then use it like this
<div className={`border-2 ${getColor}`}> hello world </div>

How to add custom colors name on Material UI with TypeScript?

I am working with Material UI with TypeScript and want to add custom colors to my theme. Everything is working fine, except the VSCode linter that show me the next message.
Type '{ tan: string; lightRed: string; red: string; offBlack: string; white: string; }' is not assignable to type 'Partial<CommonColors>'.
Object literal may only specify known properties, and 'tan' does not exist in type 'Partial<CommonColors>'.
In terms of develop and build is working fine, the only complain is the error message. I add a custom type to try to solve but it is not working.
const theme = createTheme({
palette: {
common: {
tan,
lightRed,
red,
offBlack,
white,
},
},
});
import {
PaletteOptions,
CommonColors,
} from '#material-ui/core/styles/createPalette';
interface CustomColors extends CommonColors {
tan: string?;
lightRed: string;
red: string;
offBlack: string;
}
declare module '#material-ui/core/styles/createPalette' {
export interface PaletteOptions {
common: CustomColors;
}
}
I added to the tsconfig.json file. The tan, red and the rest of values are declared as Strings. Any clue about how can I solve this? Thanks in advance.
I can't claim to have a good understanding of module augmentation, but I have done it in my own app (also for custom colors in the palette) and when I use the same approach as in my own app, it works for your scenario. My understanding is that you only have to specify the augmentation -- you don't need to create new types extending the existing ones. In your case, you just want to augment CommonColors.
The following approach seems to work:
import "#mui/material/styles/createPalette";
declare module "#mui/material/styles/createPalette" {
interface CommonColors {
tan: string;
lightRed: string;
red: string;
offBlack: string;
}
}
In my example, I placed this code in a createPalette.d.ts file and the name of that file does seem to matter (though it doesn't seem to matter what directory it is in as long as it is within the directories looked at by the compiler). It also works fine to put the code directly in index.tsx or directly in the TypeScript file that executes createTheme.
Related answers:
Typescript Module augmentation is not working: Property 'main' does not exist on type 'PaletteColorOptions'
MUI Override Slider color options with module augmentation

Override default component settings in grapesjs?

I am using GrapesJS in a CMS. By default, added blocks come with component settings defined in this file:
https://github.com/artf/grapesjs/blob/dev/src/dom_components/model/Component.js
How do I override the default component settings so they can be applied globally to all components within my custom blocks?
This is how I do it:
grapesEditor.BlockManager.get('image').set({
content: { style: 'color: "black"; max-width: 962px;' },
});
Where grapesEditor is the instance of the editor that you get when initalizing it.
Is there a way to update defaults for built-in components? I have bold text inside element. All bold elements should have default highlighted: false. I tried this config but no success
Editor.DomComponents.addType('text', {
model: {
defaults: {
tagName: 'b',
highlightable: false,
}
}
});
I don't use any storageManager and elements b, i etc. are always highlighted. When I use storageManager local, element are ok and not highlighted.

Reading an array from another Class

I have a Class on a Theme.swift called Themes file which basically defines some types of Strings, and set different colours and font types.
On another file, called Contents.swift I have another class called Contents, and some arrays, like this:
class Contents: Themes {
let navContent = [
LabelContent(text: "NAV IDENT", theme: .menuOption),
LabelContent(text: "WPT LIST", theme: .menuOption)
]
}
The question is:
How can I use this navContent array in AppDelegate? It's not global yet I think.
If you don't want to create an instance of the class Contents and then get its properties, then make those properties static (or Type Properties):
class Contents: Themes {
static let navContent = [
LabelContent(text: "NAV IDENT", theme: .menuOption),
LabelContent(text: "WPT LIST", theme: .menuOption)
]
}
And you could access them like so:
print(Contents.navContent[0])
Here is a brief description of Type Properties from the documentation:
You can define properties that belong to the type itself, not to any one instance of that type. There will only ever be one copy of these properties, no matter how many instances of that type you create. These kinds of properties are called type properties.
if it's a member variable of the Contents class as you have it there, you need to create an instance of Contents, then access it from the instance
let instance = Contents()
instance.navContent // access it this way
if you dont want to create an instance everytime you need to access it, then you can make it into static class variable
class Contents: Themes {
static let navContent = [
LabelContent(text: "NAV IDENT", theme: .menuOption),
LabelContent(text: "WPT LIST", theme: .menuOption)
]
}
Contents.navContent // access it this way
if you need polymorphism on that variable, you can use the 'class' keyword on the variable and you can override it on the child class (but it needs to be a computed variable). you access it the same way as static class variable
class Contents: Themes {
class var navContent: [LabelContent] {
return [LabelContent(text: "NAV IDENT", theme: .menuOption)]
}
}
class OtherContents: Contents {
override class var navContent: [LabelContent] {
return [LabelContent(text: "WPT LIST", theme: .menuOption)]
}
}
Contents.navContent // access "NAV IDENT"
OtherContents.navContent // access "WPT LIST"

Resources