ts howto
- react 声明 state(
ReadOnly
)属性 - TODO: research on
.d.ts
- BEST-PRACTICE: how to define const array with types
htmlFor
inlabel
- private property in interface
- [Give Up] typeorm find error types
- instanceof --> istypeof ?
- PASS: declare const array in d.ts
- hwo to define
useImperativeHandler
interface - how to design interface with default value
- what's
TS_NODE_TRANSPILE_ONLY
- TODO: cast enum to string
- how to import
.md
like resources - how to check object's specific type when defined as a union type
react 声明 state(ReadOnly
)属性
先Props
,再State
。
interface State {
bar: number;
}
interface Props {
baz: number;
}
class Foo extends React.Component<Props, State> {
public state: State = {
bar: 5,
};
}
ref:
TODO: research on .d.ts
BEST-PRACTICE: how to define const array with types
webstorm typescript live template
export const $ConstVAR$ = '$VAR$';
export type $VAR$ = typeof $ConstVAR$;
$END$;
sample source code
// sample of one unit
export const errorInvalidSuffix = 'ErrorInvalidSuffix';
export type ErrorInvalidSuffix = typeof errorInvalidSuffix;
export const errorUnknownEncoding = 'ErrorUnknownEncoding';
export type ErrorUnknownEncoding = typeof errorUnknownEncoding;
export const errorPreParsingRows = [
errorInvalidSuffix, // 后缀
errorUnknownEncoding, // 编码
] as const;
export type ErrorPreParsingRows = typeof errorPreParsingRows[number];
// sample of joining units
export const errorParsingFiles = [
...errorPreParsingRows, // 解析行之前的问题
...errorParsingRows, // 解析行时的问题
] as const;
export type ErrorParsingFile = typeof errorParsingFiles[number];
a little reflection
After a little try of this camel case const varied types, I found it a bit inflexible.
So I finally turns into the usage of simple const === type
, especially support for the use of redux actions.
htmlFor
in label
In materialUI, they used a custom element based on input
with a label
.
// https://mui.com/zh/components/buttons/#upload-button
const Input = styled('input')({
display: 'none',
});
export default function UploadButtons() {
return (
<Stack direction="row" alignItems="center" spacing={2}>
<label htmlFor="contained-button-file">
<Input
accept="image/*"
id="contained-button-file"
multiple
type="file"
/>
<Button variant="contained" component="span">
Upload
</Button>
</label>
...
</Stack>
);
}
In this demo, the label
has a property of htmlFor
, which points to an element with id of contained-button-file
, i.e the element of Input
which accepts images.
However, this may cause the eslint problem since in eslint the label should points to an built-in element.
There are 2 solutions.
add the eslint configuration:
refer to here: Case: My label and input components are custom components., we can add the configuration of custom elements as the following:
// .eslintrc
{
"rules": {
"jsx-a11y/label-has-associated-control": [
2,
{
"labelComponents": ["CustomInputLabel"],
"labelAttributes": ["label"],
"controlComponents": ["CustomInput"],
"depth": 3
}
]
}
}give up the custom elements if unnecessary
In our demo, since MaterialUI just does one little work on the built-in element of
input
, i.e. adds thedisplay: 'none'
style onto the element.So if we don't have the requirement of re-using this element, we can avoid using custom elements, and re-write the codes like the following:
export default function UploadButtons() {
return (
<Stack direction="row" alignItems="center" spacing={2}>
<label htmlFor="contained-button-file">
<input
style={{display: 'none'}}
accept="image/*"
id="contained-button-file"
multiple
type="file"
/>
<Button variant="contained" component="span">
Upload
</Button>
</label>
...
</Stack>
);
}
private property in interface
I intended to make the property from interface into implemented class private, so that I can use methods to export those properties, but to find it's impossible.
// src/main/modules/parseFile/handler/parse_base.ts:16
export interface IParseResult {
startTime: Date;
parseEndTime: Date;
dbEndTime: Date;
parseMileSeconds: number;
dbMileSeconds: number;
nTotalRows: number;
nSavedRows: number;
nFailedValidation: number;
sizePct: number;
rowsPct: number;
}
And actually what I want to do is because I didn't catch really what an interface means, and how to design a robust interface with class.
The IParseResult
is really what I want, that means, the exported data-structure.
However, I cannot use a class to implement directly on this interface, so that I operate the public methods inner the class to alter these properties.
The proper way is to define a class to store all or partial data properties of this interface, and do operations, and then, finally export those values.
If I do not want to export each time, since I want to use a variable like parseResult
directly in the scope, then I can design a class with accepts the parseResult
then alter its value by methods so that the changes happen in place.
In conclusion, we can define an interface, and the interface is for outer usage, rather than implemented by a class, which, if so, needs to be implemented like this:
interface IPipeParseResult {
...
export: () => IParseResult
}
class ParseResult implements IPipeParseResult {
...
public expo
rt(): IParseResult {
return {
...
}
}
}
Not like this, which has no meaning:
class ParseResult implements IParseResult {
....
}
So, to my former project, I gave it up, since no need to be that sophisticated then.
ref:
[Give Up] typeorm find error types
I intended to use error type to check the database execution result.
However, I failed, since the specific error type is not provided by the typeorm
instead of from third party library like sqlite3-driver
or so.
The query result module is written at typeorm/QueryBuilder.ts at beea2e1e4429d13d7864ebc23aa6e58fa01647ea · typeorm/typeorm, in which it just merges the third-party query result with typeorm's inner query result defined at typeorm/QueryFailedError.ts at beea2e1e4429d13d7864ebc23aa6e58fa01647ea · typeorm/typeorm.
Hence, unless we spent a lot of time to figure out what the lib is using and where the types of the lib defines, (and possibly we could find nothing since they may be written via C/C++
).
So just let it go, and do more harding coding then. Those don't deserve.
instanceof --> istypeof ?
No! In typescript, there is no api like instanceof
to type check.
However, we can define a method which returns a is A
to determine.
ref:
PASS: declare const array in d.ts
temporary solution: use enum
instead of const array
ref:
hwo to define useImperativeHandler
interface
It's quite clarified in this answer that when I define a useImperativeHandler
, I need to make at least four steps.
First, I should let the useRef
know not only the component type (which initialized as null
) but also the Handler
type, in which defined the api interface, so that I can use ref.current.doSomething()
and share the full auto-complement from IDE.
Second, how to define the Handler
type? The easier way is derive it directly from the component using typeof ForwardRefType
.
However, if we hadn't defined what's the Handler
we are to use in our ForwardRefType
, then those work still wouldn't work. It forced us to clearly define the Handler
the component
is using.
Nevertheless, I am not willing to write an interface which is totally equal to the type of function. So I struggled to find a ReturnType
to help me auto complete this matter.
And I found a way to write like this:
First, I peeled off(剥离) the imperativeHandler
api separately, and the cost is to use a function since the Handler
depends the ref
.
Then I use this Handler
again, to let its ReturnType
serve as the generic type of forwardRef
(this is the most important!).
Finally, I use the type of forwardRef
as the generic type of its father ref element, and then it would know what api to use. All things are done!
There is a last problem about this approach, that is why I cannot make the ref init value work even with null as unknown as ScrollToBottom
, which forced me to write like ref?.current?.doScroll()
rather than ref.current.doScroll()
.
But it's not so important yet now. Maybe I would turn back to solve this in the future need.
[TODO: why null as unknown as ScrollToBottom
not work]
ref:
ReturnType of a function
function f1(s: string) {
return {a: 1, b: s};
}
type T14 = ReturnType<typeof f1>; // { a: number, b: string }
ref:
how to design interface with default value
There has been quite a little of insightful solutions offered in this question Typescript interface default values - Stack Overflow.
And I finally choose the factory function way since it's more straight-forward and can meet my need also.
Then my interface is designed into like this:
import {MsgFromMain, MsgLevel} from '../universal';
export interface ConsoleItem {
text: string;
time: Date;
level: MsgLevel;
}
export const makeItemFromMain = (
msg: MsgFromMain,
func?: (any) => string,
): ConsoleItem => ({
text: func ? func(msg.content) : msg.content,
time: msg.sendTime,
level: msg.level || MsgLevel.debug,
});
export const makeItemFromText = (
text: string,
level = MsgLevel.debug,
): ConsoleItem => ({
text,
time: new Date(),
level,
});
In this interface, any of text | time | level
can get a default value either from another input or so, and it frees me from redundant coding and allows me to write like this:
Thank you!
ref:
what's TS_NODE_TRANSPILE_ONLY
In a word, transpile_only
is used to fasten the transition speed from ts into js.
ref:
TODO: cast enum to string
If I define a EnumType of enum MenuKey {ERP="ERP", TRD="TRD"}
since I need a data structure to limit a variable domain.
Obviously in my case, they are all string, which means the real intension of me is something like enum MenuKey {xxx} as string
so that I can put my MenuKey
into an API which only accepts string, e.g: slice
.
Hence, I can write like the following since ts would treat mk
as a string so that has an api of slice
:
const mk: MenuKey = 'ERP';
console.log(mk.slice(0, 2));
However, it doesn't.
The only way I can do is write like this:
console.log((mk as string).slice(0, 2));
Please read another example from the real business scene:
enum MenuKey {
ERP = 'ERP',
TRD = 'TRD',
}
// first realization, definitely not good since we need to write `as string` each time using it as a string
const [menuKey, setMenuKey] = useState(MenuKey.ERP);
console.log((menuKey as string).slice(0, 2)); // not good
// second realization, a little better
const [menuKey, setMenuKey] = useState(MenuKey.ERP as string);
console.log(menuKey.slice(0, 2));
I wonder if there is a built-in practice that allows me done this right.
Thanks.
how to import .md
like resources
Just declare it as a module.
// globals.d.ts
declare module '*.md';
ref:
how to check object's specific type when defined as a union type
This problem may seem easy is many programming languages, e.g, you can use isinstane(x, X)
in python
.
However, it becomes tricky when things in TypeScript since so many that are close to complex concepts can be really hard for a newbie to find the right way.
I tried to scratch some useful info from the official TypeScript website but to find neither union
nor merge
can satisfy my requirements. The combination
may be a little helpful if we do some hook on this one.
On StackOverFlow, a relative post javascript - Is it possible to combine members of multiple types in a TypeScript annotation? - Stack Overflow caught my eyesight but indeed almost none of the answers can meet my expectation -- an built-in and elegant(优雅的) solution rather than write redundant and vulnerable(脆弱的) functions.
Finally, I found a wonderful typescript handbook named as typescript-cheatsheet
at typescript-cheatsheet | A set of TypeScript related notes used for quick reference. The cheatsheet contains references to types, classes, decorators, and many other TypeScript related subjects. , where it's easy for me to locate into the target chapter: typescript-cheatsheet | A set of TypeScript related notes used for quick reference. The cheatsheet contains references to types, classes, decorators, and many other TypeScript related subjects.
In this cheatsheet, it concludes two methods that can help me check an object's type, one by using type-guards
which is best suitable for my current need, and the other one is by using discriminators
which may be useful in the later projects.
If you are interested at discriminators
, please move a step to Typescript discriminator. Very often we have use-cases where we… | by Dixit Patel | Medium for a better understanding since I am confused it with the javascript properties
and typescript decorators
.
Thanks to typescript-cheatsheet
, it really helped me a lot and I can foresee that I will frequently seek for any typescript help from here rather than first searching on the stackoverflow.