diff --git a/README.md b/README.md index 3366e38..9e8428e 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,21 @@ -# TypeScript for Beginner Programmers +# [TypeScript for Beginner Programmers](https://ts.chibicode.com) + +### This is the repository for the TypeScript tutorial website called **[TypeScript for Beginner Programmers](https://ycombinator.chibicode.com/)**. + +

+ +

## License & Credits - For emojis, I’m using [Twemoji](https://github.com/twitter/twemoji) by Twitter (CC-BY 4.0 license). -- The text for this course is licensed under [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/). -- Everything else is licensed under the [MIT](LICENSE-non-text.txt) license. \ No newline at end of file +- The text for this website is licensed under [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/). +- Everything else is licensed under the [MIT](LICENSE-non-text.txt) license. + +## Author + +**Shu Uesugi** + +- Twitter: [@chibicode](https://twitter.com/chibicode) +- [Website](https://chibicode.com) +- Email: [shu@chibicode.com](mailto:shu@chibicode.com) \ No newline at end of file diff --git a/snippets/snippets/generics/bwyu.ts b/snippets/snippets/generics/bwyu.ts new file mode 100644 index 0000000..b02171e --- /dev/null +++ b/snippets/snippets/generics/bwyu.ts @@ -0,0 +1,5 @@ +// Confused by generics code like this? +function makePair< + F extends number | string, + S extends boolean | F +>() diff --git a/snippets/snippets/generics/cqrm.ts b/snippets/snippets/generics/cqrm.ts new file mode 100644 index 0000000..ecb38cd --- /dev/null +++ b/snippets/snippets/generics/cqrm.ts @@ -0,0 +1,6 @@ +function makePair() { + // Usage: Pass F for A and S for B + let pair: Pair + + // ... +} diff --git a/snippets/snippets/generics/gozc.ts b/snippets/snippets/generics/gozc.ts new file mode 100644 index 0000000..a07dd6d --- /dev/null +++ b/snippets/snippets/generics/gozc.ts @@ -0,0 +1,8 @@ +// Creates a (number, string) pair +const { getPair, setPair } = makePair< + number, + string +>() + +// Must pass (number, string) +setPair(1, 'hello') diff --git a/snippets/snippets/generics/jejx.ts b/snippets/snippets/generics/jejx.ts new file mode 100644 index 0000000..1ef9636 --- /dev/null +++ b/snippets/snippets/generics/jejx.ts @@ -0,0 +1,7 @@ +const { getPair, setPair } = makePair() + +setPair(1, 2) +console.log(getPair()) + +setPair(3, 4) +console.log(getPair()) diff --git a/snippets/snippets/generics/kiyi.ts b/snippets/snippets/generics/kiyi.ts deleted file mode 100644 index 572326f..0000000 --- a/snippets/snippets/generics/kiyi.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Confused by generics code like this? -function getProperty( - obj: T, - key: K -) diff --git a/snippets/snippets/generics/lldl.ts b/snippets/snippets/generics/lldl.ts new file mode 100644 index 0000000..6252f2d --- /dev/null +++ b/snippets/snippets/generics/lldl.ts @@ -0,0 +1,6 @@ +// Extract into a generic interface +// to make it reusable +interface Pair { + first: A + second: B +} diff --git a/snippets/snippets/generics/mroc.ts b/snippets/snippets/generics/mroc.ts new file mode 100644 index 0000000..aa20fe5 --- /dev/null +++ b/snippets/snippets/generics/mroc.ts @@ -0,0 +1,11 @@ +class State { + state: S + + getState() { + return this.state + } + + setState(x: S) { + this.state = x + } +} diff --git a/snippets/snippets/generics/mrub.ts b/snippets/snippets/generics/mrub.ts new file mode 100644 index 0000000..50d403b --- /dev/null +++ b/snippets/snippets/generics/mrub.ts @@ -0,0 +1,5 @@ +function makePair() { + let pair: { first: F; second: S } + + // ... +} diff --git a/snippets/snippets/generics/nbvo.ts b/snippets/snippets/generics/nbvo.ts new file mode 100644 index 0000000..025f921 --- /dev/null +++ b/snippets/snippets/generics/nbvo.ts @@ -0,0 +1,4 @@ +function makePair< + F extends number | string = number, + S extends number | string = number +>() diff --git a/snippets/snippets/generics/pjcw.ts b/snippets/snippets/generics/pjcw.ts index 7651775..09b1c54 100644 --- a/snippets/snippets/generics/pjcw.ts +++ b/snippets/snippets/generics/pjcw.ts @@ -1,4 +1,4 @@ -// Set default value of x +// Set the default value of x function regularFunc(x = 2) // x will be 2 inside the function diff --git a/snippets/snippets/generics/qgea.ts b/snippets/snippets/generics/qgea.ts new file mode 100644 index 0000000..b53124c --- /dev/null +++ b/snippets/snippets/generics/qgea.ts @@ -0,0 +1,6 @@ +// Extract into a generic type alias. It’s +// basically identical to using an interface +type Pair = { + first: A + second: B +} diff --git a/snippets/snippets/generics/qgxj.ts b/snippets/snippets/generics/qgxj.ts new file mode 100644 index 0000000..159f301 --- /dev/null +++ b/snippets/snippets/generics/qgxj.ts @@ -0,0 +1,5 @@ +// makeState() has 1 type parameter +function makeState() + +// makePair() has 2 type parameters +function makePair() diff --git a/snippets/snippets/generics/qqic.ts b/snippets/snippets/generics/qqic.ts index 148d91f..362bb1c 100644 --- a/snippets/snippets/generics/qqic.ts +++ b/snippets/snippets/generics/qqic.ts @@ -1,7 +1,7 @@ // Doesn't work because the created state… const numAndStrState = makeState() -// Supports both numbers… +// Allows both numbers… numAndStrState.setState(1) console.log(numAndStrState.getState()) @@ -10,4 +10,4 @@ numAndStrState.setState('foo') console.log(numAndStrState.getState()) // This is NOT what we want. We want to create -// a number-only state, and a string-only state. +// a number-only state and a string-only state. diff --git a/snippets/snippets/generics/rxdm.ts b/snippets/snippets/generics/rxdm.ts new file mode 100644 index 0000000..2ac56af --- /dev/null +++ b/snippets/snippets/generics/rxdm.ts @@ -0,0 +1,16 @@ +function makePair() { + let pair: { first: F; second: S } + + function getPair() { + return pair + } + + function setPair(x: F, y: S) { + pair = { + first: x, + second: y + } + } + + return { getPair, setPair } +} diff --git a/snippets/snippets/generics/thxf.ts b/snippets/snippets/generics/thxf.ts index 24deecd..9c42a1a 100644 --- a/snippets/snippets/generics/thxf.ts +++ b/snippets/snippets/generics/thxf.ts @@ -1,4 +1,4 @@ -// Set default type of S as number +// Set the default type of S as number function makeState< S extends number | string = number >() diff --git a/snippets/snippets/generics/ugeb.ts b/snippets/snippets/generics/ugeb.ts new file mode 100644 index 0000000..7e671ab --- /dev/null +++ b/snippets/snippets/generics/ugeb.ts @@ -0,0 +1,18 @@ +function makePair() { + // Stores a pair of values + let pair: { first: number; second: number } + + function getPair() { + return pair + } + + // Stores x as first and y as second + function setPair(x: number, y: number) { + pair = { + first: x, + second: y + } + } + + return { getPair, setPair } +} diff --git a/snippets/snippets/generics/xekh.ts b/snippets/snippets/generics/xekh.ts new file mode 100644 index 0000000..050ced4 --- /dev/null +++ b/snippets/snippets/generics/xekh.ts @@ -0,0 +1,17 @@ +// The second parameter S must be either +// boolean or whatever was specified for F +function makePair< + F extends number | string, + S extends boolean | F +>() + +// These will work +makePair() +makePair() +makePair() +makePair() + +// This will fail because the second +// parameter must extend boolean | number, +// but instead it’s string +makePair() diff --git a/snippets/snippets/generics/zdbq.ts b/snippets/snippets/generics/zdbq.ts new file mode 100644 index 0000000..48bf819 --- /dev/null +++ b/snippets/snippets/generics/zdbq.ts @@ -0,0 +1,7 @@ +// Pass a type parameter on initialization +const numState = new State() + +numState.setState(1) + +// Prints 1 +console.log(numState.getState()) diff --git a/src/components/ContentTags/A.tsx b/src/components/ContentTags/A.tsx new file mode 100644 index 0000000..e443239 --- /dev/null +++ b/src/components/ContentTags/A.tsx @@ -0,0 +1,21 @@ +/** @jsx jsx */ +import { css, jsx } from '@emotion/core' +import useTheme from 'src/hooks/useTheme' + +const A = (props: JSX.IntrinsicElements['a']) => { + const { colors } = useTheme() + return ( + + ) +} + +export default A diff --git a/src/components/ContentTags/Code.tsx b/src/components/ContentTags/Code.tsx index f50a1c7..3f3e345 100644 --- a/src/components/ContentTags/Code.tsx +++ b/src/components/ContentTags/Code.tsx @@ -1,8 +1,12 @@ /** @jsx jsx */ import { css, jsx } from '@emotion/core' import useTheme from 'src/hooks/useTheme' +import { allColors } from 'src/lib/theme/colors' -const Code = (props: JSX.IntrinsicElements['code']) => { +const Code = ({ + color, + ...props +}: JSX.IntrinsicElements['code'] & { color?: keyof typeof allColors }) => { const { colors } = useTheme() return ( { css` font-size: 0.9em; word-break: break-word; - background: ${colors('lightPink2')}; + background: ${color ? colors(color) : colors('lightPink2')}; ` ]} /> diff --git a/src/components/ContentTags/index.tsx b/src/components/ContentTags/index.tsx index 1aa7480..01b1846 100644 --- a/src/components/ContentTags/index.tsx +++ b/src/components/ContentTags/index.tsx @@ -3,4 +3,5 @@ export { default as H3 } from 'src/components/ContentTags/H3' export { default as Code } from 'src/components/ContentTags/Code' export { default as Highlight } from 'src/components/ContentTags/Highlight' export { default as Hr } from 'src/components/ContentTags/Hr' +export { default as A } from 'src/components/ContentTags/A' export { Ul, Ol, UlLi, OlLi } from 'src/components/ContentTags/List' diff --git a/src/components/Emoji/SmilingCat.tsx b/src/components/Emoji/SmilingCat.tsx new file mode 100644 index 0000000..0159207 --- /dev/null +++ b/src/components/Emoji/SmilingCat.tsx @@ -0,0 +1,40 @@ +import React from 'react' + +const SvgSparkles = (props: React.SVGProps) => ( + + + + + + + + + + + + + +) + +export default SvgSparkles diff --git a/src/components/Emoji/Sparkles.tsx b/src/components/Emoji/Sparkles.tsx new file mode 100644 index 0000000..f0bf560 --- /dev/null +++ b/src/components/Emoji/Sparkles.tsx @@ -0,0 +1,16 @@ +import React from 'react' + +const SvgSmilingCat = (props: React.SVGProps) => ( + + + + +) + +export default SvgSmilingCat diff --git a/src/components/Emoji/index.tsx b/src/components/Emoji/index.tsx index cba72f7..aabdb2f 100644 --- a/src/components/Emoji/index.tsx +++ b/src/components/Emoji/index.tsx @@ -6,6 +6,8 @@ import Question from 'src/components/Emoji/Question' import Run from 'src/components/Emoji/Run' import ChickEgg from 'src/components/Emoji/ChickEgg' import Twitter from 'src/components/Emoji/Twitter' +import Sparkles from 'src/components/Emoji/Sparkles' +import SmilingCat from 'src/components/Emoji/SmilingCat' export const emojiToComponent = { bird: Bird, @@ -13,7 +15,9 @@ export const emojiToComponent = { question: Question, run: Run, chickEgg: ChickEgg, - twitter: Twitter + twitter: Twitter, + sparkles: Sparkles, + smilingCat: SmilingCat } const Emoji = ({ diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx new file mode 100644 index 0000000..b0efa88 --- /dev/null +++ b/src/components/Footer.tsx @@ -0,0 +1,32 @@ +/** @jsx jsx */ +import { css, jsx } from '@emotion/core' +import Container from 'src/components/Container' +import useTheme from 'src/hooks/useTheme' +import { A } from 'src/components/ContentTags' + +const Footer = () => { + const { fontSizes, ns, spaces, colors } = useTheme() + + return ( + + The source code for this site is{' '} + + available on GitHub + + . + + ) +} + +export default Footer diff --git a/src/components/IndexPage.tsx b/src/components/IndexPage.tsx new file mode 100644 index 0000000..796bd24 --- /dev/null +++ b/src/components/IndexPage.tsx @@ -0,0 +1,113 @@ +/** @jsx jsx */ +import { css, jsx } from '@emotion/core' +import Page from 'src/components/Page' +import InternalLink from 'src/components/InternalLink' +import useTheme from 'src/hooks/useTheme' +import { articlesList, articlesData } from 'src/lib/articles' +import { dateString } from 'src/lib/date' + +const ArticleLink = ({ + title, + href, + date +}: { + title: string + href: string + date: string +}) => { + const { + colors, + ns, + fontSizes, + spaces, + lineHeights, + letterSpacings + } = useTheme() + return ( +
  • +

    + + {title} + +

    +

    + {date} +

    +
  • + ) +} + +const IndexPage = ({ children }: { children: React.ReactNode }) => { + const { ns, spaces, fontSizes, letterSpacings, colors } = useTheme() + return ( + + {children} +

    + Articles +

    +
      + {articlesList.map(articleKey => ( + + ))} +
    +
    + ) +} + +export default IndexPage diff --git a/src/components/Page.tsx b/src/components/Page.tsx index 5e5875e..4e3802f 100644 --- a/src/components/Page.tsx +++ b/src/components/Page.tsx @@ -4,6 +4,7 @@ import GlobalStyles from 'src/components/GlobalStyles' import Head from 'next/head' import Container from 'src/components/Container' import Header from 'src/components/Header' +import Footer from 'src/components/Footer' import useTheme from 'src/hooks/useTheme' const Page = ({ @@ -49,16 +50,18 @@ const Page = ({ +